From a9f5aa1cc96fc2c71f19a9c3e9dcbee0e78f83ca Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 15 Nov 2005 03:13:04 +0000 Subject: rename current stable linuxthreads to linuxthreads.old to prepare for import of latest glibc version --- libpthread/linuxthreads.old/Changes | 85 + libpthread/linuxthreads.old/FAQ.html | 1039 +++++++++++++ libpthread/linuxthreads.old/LICENSE | 501 ++++++ libpthread/linuxthreads.old/Makefile | 15 + libpthread/linuxthreads.old/Makefile.in | 62 + libpthread/linuxthreads.old/README | 166 ++ libpthread/linuxthreads.old/attr.c | 214 +++ libpthread/linuxthreads.old/cancel.c | 184 +++ libpthread/linuxthreads.old/condvar.c | 296 ++++ libpthread/linuxthreads.old/debug.h | 56 + libpthread/linuxthreads.old/errno.c | 37 + libpthread/linuxthreads.old/events.c | 37 + libpthread/linuxthreads.old/internals.h | 518 +++++++ libpthread/linuxthreads.old/join.c | 221 +++ libpthread/linuxthreads.old/linuxthreads.texi | 1627 ++++++++++++++++++++ libpthread/linuxthreads.old/locale.c | 58 + libpthread/linuxthreads.old/lockfile.c | 39 + libpthread/linuxthreads.old/manager.c | 905 +++++++++++ libpthread/linuxthreads.old/mutex.c | 356 +++++ libpthread/linuxthreads.old/oldsemaphore.c | 235 +++ libpthread/linuxthreads.old/pt-machine.c | 22 + libpthread/linuxthreads.old/ptfork.c | 126 ++ libpthread/linuxthreads.old/pthread.c | 1044 +++++++++++++ libpthread/linuxthreads.old/pthread.c-OLDEXAMPLE | 121 ++ libpthread/linuxthreads.old/ptlongjmp.c | 55 + libpthread/linuxthreads.old/queue.h | 61 + libpthread/linuxthreads.old/restart.h | 50 + libpthread/linuxthreads.old/rwlock.c | 486 ++++++ libpthread/linuxthreads.old/semaphore.c | 308 ++++ libpthread/linuxthreads.old/semaphore.h | 87 ++ libpthread/linuxthreads.old/signals.c | 248 +++ libpthread/linuxthreads.old/specific.c | 204 +++ libpthread/linuxthreads.old/spinlock.c | 723 +++++++++ libpthread/linuxthreads.old/spinlock.h | 218 +++ .../linuxthreads.old/sysdeps/alpha/pt-machine.h | 128 ++ .../linuxthreads.old/sysdeps/arm/pt-machine.h | 70 + .../linuxthreads.old/sysdeps/bfin/pt-machine.h | 57 + .../linuxthreads.old/sysdeps/cris/pt-machine.h | 58 + .../linuxthreads.old/sysdeps/frv/pt-machine.h | 68 + .../linuxthreads.old/sysdeps/i386/pt-machine.h | 158 ++ libpthread/linuxthreads.old/sysdeps/i386/tls.h | 185 +++ libpthread/linuxthreads.old/sysdeps/i386/useldt.h | 307 ++++ .../linuxthreads.old/sysdeps/m68k/pt-machine.h | 76 + .../linuxthreads.old/sysdeps/mips/pt-machine.h | 110 ++ .../linuxthreads.old/sysdeps/nios/pt-machine.h | 67 + .../linuxthreads.old/sysdeps/nios2/pt-machine.h | 58 + .../linuxthreads.old/sysdeps/powerpc/pt-machine.h | 103 ++ .../sysdeps/pthread/bits/libc-lock.h | 328 ++++ .../sysdeps/pthread/bits/libc-tsd.h | 66 + .../sysdeps/pthread/bits/pthreadtypes.h | 142 ++ .../linuxthreads.old/sysdeps/pthread/pthread.h | 705 +++++++++ libpthread/linuxthreads.old/sysdeps/pthread/tls.h | 81 + .../linuxthreads.old/sysdeps/sh/pt-machine.h | 81 + libpthread/linuxthreads.old/sysdeps/sh/tls.h | 117 ++ .../linuxthreads.old/sysdeps/sh64/Makefile.arch | 26 + .../linuxthreads.old/sysdeps/sh64/pt-machine.c | 47 + .../linuxthreads.old/sysdeps/sh64/pt-machine.h | 36 + .../linuxthreads.old/sysdeps/sparc/pt-machine.h | 8 + .../sysdeps/sparc/sparc32/pt-machine.h | 83 + .../sysdeps/sparc/sparc64/pt-machine.h | 105 ++ .../linuxthreads.old/sysdeps/v850/pt-machine.h | 46 + .../linuxthreads.old/sysdeps/x86_64/pt-machine.h | 86 ++ libpthread/linuxthreads.old/sysdeps/x86_64/tls.h | 134 ++ libpthread/linuxthreads.old/wrapsyscall.c | 220 +++ libpthread/linuxthreads.old_db/Banner | 1 + libpthread/linuxthreads.old_db/Makefile | 15 + libpthread/linuxthreads.old_db/Makefile.in | 43 + libpthread/linuxthreads.old_db/Versions | 21 + libpthread/linuxthreads.old_db/proc_service.h | 70 + libpthread/linuxthreads.old_db/td_init.c | 32 + libpthread/linuxthreads.old_db/td_log.c | 32 + libpthread/linuxthreads.old_db/td_symbol_list.c | 56 + libpthread/linuxthreads.old_db/td_ta_clear_event.c | 53 + libpthread/linuxthreads.old_db/td_ta_delete.c | 58 + .../linuxthreads.old_db/td_ta_enable_stats.c | 35 + libpthread/linuxthreads.old_db/td_ta_event_addr.c | 73 + .../linuxthreads.old_db/td_ta_event_getmsg.c | 129 ++ .../linuxthreads.old_db/td_ta_get_nthreads.c | 42 + libpthread/linuxthreads.old_db/td_ta_get_ph.c | 36 + libpthread/linuxthreads.old_db/td_ta_get_stats.c | 35 + libpthread/linuxthreads.old_db/td_ta_map_id2thr.c | 79 + libpthread/linuxthreads.old_db/td_ta_map_lwp2thr.c | 91 ++ libpthread/linuxthreads.old_db/td_ta_new.c | 150 ++ libpthread/linuxthreads.old_db/td_ta_reset_stats.c | 35 + libpthread/linuxthreads.old_db/td_ta_set_event.c | 53 + .../linuxthreads.old_db/td_ta_setconcurrency.c | 35 + libpthread/linuxthreads.old_db/td_ta_thr_iter.c | 174 +++ libpthread/linuxthreads.old_db/td_ta_tsd_iter.c | 56 + .../linuxthreads.old_db/td_thr_clear_event.c | 62 + libpthread/linuxthreads.old_db/td_thr_dbresume.c | 30 + libpthread/linuxthreads.old_db/td_thr_dbsuspend.c | 30 + .../linuxthreads.old_db/td_thr_event_enable.c | 57 + .../linuxthreads.old_db/td_thr_event_getmsg.c | 65 + libpthread/linuxthreads.old_db/td_thr_get_info.c | 83 + libpthread/linuxthreads.old_db/td_thr_getfpregs.c | 58 + libpthread/linuxthreads.old_db/td_thr_getgregs.c | 58 + libpthread/linuxthreads.old_db/td_thr_getxregs.c | 30 + .../linuxthreads.old_db/td_thr_getxregsize.c | 30 + libpthread/linuxthreads.old_db/td_thr_set_event.c | 62 + libpthread/linuxthreads.old_db/td_thr_setfpregs.c | 47 + libpthread/linuxthreads.old_db/td_thr_setgregs.c | 47 + libpthread/linuxthreads.old_db/td_thr_setprio.c | 30 + .../linuxthreads.old_db/td_thr_setsigpending.c | 31 + libpthread/linuxthreads.old_db/td_thr_setxregs.c | 30 + libpthread/linuxthreads.old_db/td_thr_sigsetmask.c | 30 + .../linuxthreads.old_db/td_thr_tls_get_addr.c | 70 + libpthread/linuxthreads.old_db/td_thr_tsd.c | 82 + libpthread/linuxthreads.old_db/td_thr_validate.c | 70 + libpthread/linuxthreads.old_db/thread_db.h | 451 ++++++ libpthread/linuxthreads.old_db/thread_dbP.h | 110 ++ libpthread/linuxthreads/Changes | 85 - libpthread/linuxthreads/FAQ.html | 1039 ------------- libpthread/linuxthreads/LICENSE | 501 ------ libpthread/linuxthreads/Makefile | 15 - libpthread/linuxthreads/Makefile.in | 62 - libpthread/linuxthreads/README | 166 -- libpthread/linuxthreads/attr.c | 214 --- libpthread/linuxthreads/cancel.c | 184 --- libpthread/linuxthreads/condvar.c | 296 ---- libpthread/linuxthreads/debug.h | 56 - libpthread/linuxthreads/errno.c | 37 - libpthread/linuxthreads/events.c | 37 - libpthread/linuxthreads/internals.h | 518 ------- libpthread/linuxthreads/join.c | 221 --- libpthread/linuxthreads/linuxthreads.texi | 1627 -------------------- libpthread/linuxthreads/locale.c | 58 - libpthread/linuxthreads/lockfile.c | 39 - libpthread/linuxthreads/manager.c | 905 ----------- libpthread/linuxthreads/mutex.c | 356 ----- libpthread/linuxthreads/oldsemaphore.c | 235 --- libpthread/linuxthreads/pt-machine.c | 22 - libpthread/linuxthreads/ptfork.c | 126 -- libpthread/linuxthreads/pthread.c | 1044 ------------- libpthread/linuxthreads/pthread.c-OLDEXAMPLE | 121 -- libpthread/linuxthreads/ptlongjmp.c | 55 - libpthread/linuxthreads/queue.h | 61 - libpthread/linuxthreads/restart.h | 50 - libpthread/linuxthreads/rwlock.c | 486 ------ libpthread/linuxthreads/semaphore.c | 308 ---- libpthread/linuxthreads/semaphore.h | 87 -- libpthread/linuxthreads/signals.c | 248 --- libpthread/linuxthreads/specific.c | 204 --- libpthread/linuxthreads/spinlock.c | 723 --------- libpthread/linuxthreads/spinlock.h | 218 --- libpthread/linuxthreads/sysdeps/alpha/pt-machine.h | 128 -- libpthread/linuxthreads/sysdeps/arm/pt-machine.h | 70 - libpthread/linuxthreads/sysdeps/bfin/pt-machine.h | 57 - libpthread/linuxthreads/sysdeps/cris/pt-machine.h | 58 - libpthread/linuxthreads/sysdeps/frv/pt-machine.h | 68 - libpthread/linuxthreads/sysdeps/i386/pt-machine.h | 158 -- libpthread/linuxthreads/sysdeps/i386/tls.h | 185 --- libpthread/linuxthreads/sysdeps/i386/useldt.h | 307 ---- libpthread/linuxthreads/sysdeps/m68k/pt-machine.h | 76 - libpthread/linuxthreads/sysdeps/mips/pt-machine.h | 110 -- libpthread/linuxthreads/sysdeps/nios/pt-machine.h | 67 - libpthread/linuxthreads/sysdeps/nios2/pt-machine.h | 58 - .../linuxthreads/sysdeps/powerpc/pt-machine.h | 103 -- .../linuxthreads/sysdeps/pthread/bits/libc-lock.h | 328 ---- .../linuxthreads/sysdeps/pthread/bits/libc-tsd.h | 66 - .../sysdeps/pthread/bits/pthreadtypes.h | 142 -- libpthread/linuxthreads/sysdeps/pthread/pthread.h | 705 --------- libpthread/linuxthreads/sysdeps/pthread/tls.h | 81 - libpthread/linuxthreads/sysdeps/sh/pt-machine.h | 81 - libpthread/linuxthreads/sysdeps/sh/tls.h | 117 -- libpthread/linuxthreads/sysdeps/sh64/Makefile.arch | 26 - libpthread/linuxthreads/sysdeps/sh64/pt-machine.c | 47 - libpthread/linuxthreads/sysdeps/sh64/pt-machine.h | 36 - libpthread/linuxthreads/sysdeps/sparc/pt-machine.h | 8 - .../sysdeps/sparc/sparc32/pt-machine.h | 83 - .../sysdeps/sparc/sparc64/pt-machine.h | 105 -- libpthread/linuxthreads/sysdeps/v850/pt-machine.h | 46 - .../linuxthreads/sysdeps/x86_64/pt-machine.h | 86 -- libpthread/linuxthreads/sysdeps/x86_64/tls.h | 134 -- libpthread/linuxthreads/wrapsyscall.c | 220 --- libpthread/linuxthreads_db/Banner | 1 - libpthread/linuxthreads_db/Makefile | 15 - libpthread/linuxthreads_db/Makefile.in | 43 - libpthread/linuxthreads_db/Versions | 21 - libpthread/linuxthreads_db/proc_service.h | 70 - libpthread/linuxthreads_db/td_init.c | 32 - libpthread/linuxthreads_db/td_log.c | 32 - libpthread/linuxthreads_db/td_symbol_list.c | 56 - libpthread/linuxthreads_db/td_ta_clear_event.c | 53 - libpthread/linuxthreads_db/td_ta_delete.c | 58 - libpthread/linuxthreads_db/td_ta_enable_stats.c | 35 - libpthread/linuxthreads_db/td_ta_event_addr.c | 73 - libpthread/linuxthreads_db/td_ta_event_getmsg.c | 129 -- libpthread/linuxthreads_db/td_ta_get_nthreads.c | 42 - libpthread/linuxthreads_db/td_ta_get_ph.c | 36 - libpthread/linuxthreads_db/td_ta_get_stats.c | 35 - libpthread/linuxthreads_db/td_ta_map_id2thr.c | 79 - libpthread/linuxthreads_db/td_ta_map_lwp2thr.c | 91 -- libpthread/linuxthreads_db/td_ta_new.c | 150 -- libpthread/linuxthreads_db/td_ta_reset_stats.c | 35 - libpthread/linuxthreads_db/td_ta_set_event.c | 53 - libpthread/linuxthreads_db/td_ta_setconcurrency.c | 35 - libpthread/linuxthreads_db/td_ta_thr_iter.c | 174 --- libpthread/linuxthreads_db/td_ta_tsd_iter.c | 56 - libpthread/linuxthreads_db/td_thr_clear_event.c | 62 - libpthread/linuxthreads_db/td_thr_dbresume.c | 30 - libpthread/linuxthreads_db/td_thr_dbsuspend.c | 30 - libpthread/linuxthreads_db/td_thr_event_enable.c | 57 - libpthread/linuxthreads_db/td_thr_event_getmsg.c | 65 - libpthread/linuxthreads_db/td_thr_get_info.c | 83 - libpthread/linuxthreads_db/td_thr_getfpregs.c | 58 - libpthread/linuxthreads_db/td_thr_getgregs.c | 58 - libpthread/linuxthreads_db/td_thr_getxregs.c | 30 - libpthread/linuxthreads_db/td_thr_getxregsize.c | 30 - libpthread/linuxthreads_db/td_thr_set_event.c | 62 - libpthread/linuxthreads_db/td_thr_setfpregs.c | 47 - libpthread/linuxthreads_db/td_thr_setgregs.c | 47 - libpthread/linuxthreads_db/td_thr_setprio.c | 30 - libpthread/linuxthreads_db/td_thr_setsigpending.c | 31 - libpthread/linuxthreads_db/td_thr_setxregs.c | 30 - libpthread/linuxthreads_db/td_thr_sigsetmask.c | 30 - libpthread/linuxthreads_db/td_thr_tls_get_addr.c | 70 - libpthread/linuxthreads_db/td_thr_tsd.c | 82 - libpthread/linuxthreads_db/td_thr_validate.c | 70 - libpthread/linuxthreads_db/thread_db.h | 451 ------ libpthread/linuxthreads_db/thread_dbP.h | 110 -- 220 files changed, 17127 insertions(+), 17127 deletions(-) create mode 100644 libpthread/linuxthreads.old/Changes create mode 100644 libpthread/linuxthreads.old/FAQ.html create mode 100644 libpthread/linuxthreads.old/LICENSE create mode 100644 libpthread/linuxthreads.old/Makefile create mode 100644 libpthread/linuxthreads.old/Makefile.in create mode 100644 libpthread/linuxthreads.old/README create mode 100644 libpthread/linuxthreads.old/attr.c create mode 100644 libpthread/linuxthreads.old/cancel.c create mode 100644 libpthread/linuxthreads.old/condvar.c create mode 100644 libpthread/linuxthreads.old/debug.h create mode 100644 libpthread/linuxthreads.old/errno.c create mode 100644 libpthread/linuxthreads.old/events.c create mode 100644 libpthread/linuxthreads.old/internals.h create mode 100644 libpthread/linuxthreads.old/join.c create mode 100644 libpthread/linuxthreads.old/linuxthreads.texi create mode 100644 libpthread/linuxthreads.old/locale.c create mode 100644 libpthread/linuxthreads.old/lockfile.c create mode 100644 libpthread/linuxthreads.old/manager.c create mode 100644 libpthread/linuxthreads.old/mutex.c create mode 100644 libpthread/linuxthreads.old/oldsemaphore.c create mode 100644 libpthread/linuxthreads.old/pt-machine.c create mode 100644 libpthread/linuxthreads.old/ptfork.c create mode 100644 libpthread/linuxthreads.old/pthread.c create mode 100644 libpthread/linuxthreads.old/pthread.c-OLDEXAMPLE create mode 100644 libpthread/linuxthreads.old/ptlongjmp.c create mode 100644 libpthread/linuxthreads.old/queue.h create mode 100644 libpthread/linuxthreads.old/restart.h create mode 100644 libpthread/linuxthreads.old/rwlock.c create mode 100644 libpthread/linuxthreads.old/semaphore.c create mode 100644 libpthread/linuxthreads.old/semaphore.h create mode 100644 libpthread/linuxthreads.old/signals.c create mode 100644 libpthread/linuxthreads.old/specific.c create mode 100644 libpthread/linuxthreads.old/spinlock.c create mode 100644 libpthread/linuxthreads.old/spinlock.h create mode 100644 libpthread/linuxthreads.old/sysdeps/alpha/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/bfin/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/cris/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/frv/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/i386/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/i386/tls.h create mode 100644 libpthread/linuxthreads.old/sysdeps/i386/useldt.h create mode 100644 libpthread/linuxthreads.old/sysdeps/m68k/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/mips/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/nios/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/nios2/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/powerpc/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/pthread/bits/libc-lock.h create mode 100644 libpthread/linuxthreads.old/sysdeps/pthread/bits/libc-tsd.h create mode 100644 libpthread/linuxthreads.old/sysdeps/pthread/bits/pthreadtypes.h create mode 100644 libpthread/linuxthreads.old/sysdeps/pthread/pthread.h create mode 100644 libpthread/linuxthreads.old/sysdeps/pthread/tls.h create mode 100644 libpthread/linuxthreads.old/sysdeps/sh/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/sh/tls.h create mode 100644 libpthread/linuxthreads.old/sysdeps/sh64/Makefile.arch create mode 100644 libpthread/linuxthreads.old/sysdeps/sh64/pt-machine.c create mode 100644 libpthread/linuxthreads.old/sysdeps/sh64/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/sparc/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/sparc/sparc32/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/sparc/sparc64/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/v850/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/x86_64/pt-machine.h create mode 100644 libpthread/linuxthreads.old/sysdeps/x86_64/tls.h create mode 100644 libpthread/linuxthreads.old/wrapsyscall.c create mode 100644 libpthread/linuxthreads.old_db/Banner create mode 100644 libpthread/linuxthreads.old_db/Makefile create mode 100644 libpthread/linuxthreads.old_db/Makefile.in create mode 100644 libpthread/linuxthreads.old_db/Versions create mode 100644 libpthread/linuxthreads.old_db/proc_service.h create mode 100644 libpthread/linuxthreads.old_db/td_init.c create mode 100644 libpthread/linuxthreads.old_db/td_log.c create mode 100644 libpthread/linuxthreads.old_db/td_symbol_list.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_clear_event.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_delete.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_enable_stats.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_event_addr.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_event_getmsg.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_get_nthreads.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_get_ph.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_get_stats.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_map_id2thr.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_map_lwp2thr.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_new.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_reset_stats.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_set_event.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_setconcurrency.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_thr_iter.c create mode 100644 libpthread/linuxthreads.old_db/td_ta_tsd_iter.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_clear_event.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_dbresume.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_dbsuspend.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_event_enable.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_event_getmsg.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_get_info.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_getfpregs.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_getgregs.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_getxregs.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_getxregsize.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_set_event.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_setfpregs.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_setgregs.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_setprio.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_setsigpending.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_setxregs.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_sigsetmask.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_tls_get_addr.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_tsd.c create mode 100644 libpthread/linuxthreads.old_db/td_thr_validate.c create mode 100644 libpthread/linuxthreads.old_db/thread_db.h create mode 100644 libpthread/linuxthreads.old_db/thread_dbP.h delete mode 100644 libpthread/linuxthreads/Changes delete mode 100644 libpthread/linuxthreads/FAQ.html delete mode 100644 libpthread/linuxthreads/LICENSE delete mode 100644 libpthread/linuxthreads/Makefile delete mode 100644 libpthread/linuxthreads/Makefile.in delete mode 100644 libpthread/linuxthreads/README delete mode 100644 libpthread/linuxthreads/attr.c delete mode 100644 libpthread/linuxthreads/cancel.c delete mode 100644 libpthread/linuxthreads/condvar.c delete mode 100644 libpthread/linuxthreads/debug.h delete mode 100644 libpthread/linuxthreads/errno.c delete mode 100644 libpthread/linuxthreads/events.c delete mode 100644 libpthread/linuxthreads/internals.h delete mode 100644 libpthread/linuxthreads/join.c delete mode 100644 libpthread/linuxthreads/linuxthreads.texi delete mode 100644 libpthread/linuxthreads/locale.c delete mode 100644 libpthread/linuxthreads/lockfile.c delete mode 100644 libpthread/linuxthreads/manager.c delete mode 100644 libpthread/linuxthreads/mutex.c delete mode 100644 libpthread/linuxthreads/oldsemaphore.c delete mode 100644 libpthread/linuxthreads/pt-machine.c delete mode 100644 libpthread/linuxthreads/ptfork.c delete mode 100644 libpthread/linuxthreads/pthread.c delete mode 100644 libpthread/linuxthreads/pthread.c-OLDEXAMPLE delete mode 100644 libpthread/linuxthreads/ptlongjmp.c delete mode 100644 libpthread/linuxthreads/queue.h delete mode 100644 libpthread/linuxthreads/restart.h delete mode 100644 libpthread/linuxthreads/rwlock.c delete mode 100644 libpthread/linuxthreads/semaphore.c delete mode 100644 libpthread/linuxthreads/semaphore.h delete mode 100644 libpthread/linuxthreads/signals.c delete mode 100644 libpthread/linuxthreads/specific.c delete mode 100644 libpthread/linuxthreads/spinlock.c delete mode 100644 libpthread/linuxthreads/spinlock.h delete mode 100644 libpthread/linuxthreads/sysdeps/alpha/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/arm/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/bfin/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/cris/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/frv/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/i386/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/i386/tls.h delete mode 100644 libpthread/linuxthreads/sysdeps/i386/useldt.h delete mode 100644 libpthread/linuxthreads/sysdeps/m68k/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/mips/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/nios/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/nios2/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/powerpc/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h delete mode 100644 libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h delete mode 100644 libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h delete mode 100644 libpthread/linuxthreads/sysdeps/pthread/pthread.h delete mode 100644 libpthread/linuxthreads/sysdeps/pthread/tls.h delete mode 100644 libpthread/linuxthreads/sysdeps/sh/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/sh/tls.h delete mode 100644 libpthread/linuxthreads/sysdeps/sh64/Makefile.arch delete mode 100644 libpthread/linuxthreads/sysdeps/sh64/pt-machine.c delete mode 100644 libpthread/linuxthreads/sysdeps/sh64/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/sparc/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/v850/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/x86_64/pt-machine.h delete mode 100644 libpthread/linuxthreads/sysdeps/x86_64/tls.h delete mode 100644 libpthread/linuxthreads/wrapsyscall.c delete mode 100644 libpthread/linuxthreads_db/Banner delete mode 100644 libpthread/linuxthreads_db/Makefile delete mode 100644 libpthread/linuxthreads_db/Makefile.in delete mode 100644 libpthread/linuxthreads_db/Versions delete mode 100644 libpthread/linuxthreads_db/proc_service.h delete mode 100644 libpthread/linuxthreads_db/td_init.c delete mode 100644 libpthread/linuxthreads_db/td_log.c delete mode 100644 libpthread/linuxthreads_db/td_symbol_list.c delete mode 100644 libpthread/linuxthreads_db/td_ta_clear_event.c delete mode 100644 libpthread/linuxthreads_db/td_ta_delete.c delete mode 100644 libpthread/linuxthreads_db/td_ta_enable_stats.c delete mode 100644 libpthread/linuxthreads_db/td_ta_event_addr.c delete mode 100644 libpthread/linuxthreads_db/td_ta_event_getmsg.c delete mode 100644 libpthread/linuxthreads_db/td_ta_get_nthreads.c delete mode 100644 libpthread/linuxthreads_db/td_ta_get_ph.c delete mode 100644 libpthread/linuxthreads_db/td_ta_get_stats.c delete mode 100644 libpthread/linuxthreads_db/td_ta_map_id2thr.c delete mode 100644 libpthread/linuxthreads_db/td_ta_map_lwp2thr.c delete mode 100644 libpthread/linuxthreads_db/td_ta_new.c delete mode 100644 libpthread/linuxthreads_db/td_ta_reset_stats.c delete mode 100644 libpthread/linuxthreads_db/td_ta_set_event.c delete mode 100644 libpthread/linuxthreads_db/td_ta_setconcurrency.c delete mode 100644 libpthread/linuxthreads_db/td_ta_thr_iter.c delete mode 100644 libpthread/linuxthreads_db/td_ta_tsd_iter.c delete mode 100644 libpthread/linuxthreads_db/td_thr_clear_event.c delete mode 100644 libpthread/linuxthreads_db/td_thr_dbresume.c delete mode 100644 libpthread/linuxthreads_db/td_thr_dbsuspend.c delete mode 100644 libpthread/linuxthreads_db/td_thr_event_enable.c delete mode 100644 libpthread/linuxthreads_db/td_thr_event_getmsg.c delete mode 100644 libpthread/linuxthreads_db/td_thr_get_info.c delete mode 100644 libpthread/linuxthreads_db/td_thr_getfpregs.c delete mode 100644 libpthread/linuxthreads_db/td_thr_getgregs.c delete mode 100644 libpthread/linuxthreads_db/td_thr_getxregs.c delete mode 100644 libpthread/linuxthreads_db/td_thr_getxregsize.c delete mode 100644 libpthread/linuxthreads_db/td_thr_set_event.c delete mode 100644 libpthread/linuxthreads_db/td_thr_setfpregs.c delete mode 100644 libpthread/linuxthreads_db/td_thr_setgregs.c delete mode 100644 libpthread/linuxthreads_db/td_thr_setprio.c delete mode 100644 libpthread/linuxthreads_db/td_thr_setsigpending.c delete mode 100644 libpthread/linuxthreads_db/td_thr_setxregs.c delete mode 100644 libpthread/linuxthreads_db/td_thr_sigsetmask.c delete mode 100644 libpthread/linuxthreads_db/td_thr_tls_get_addr.c delete mode 100644 libpthread/linuxthreads_db/td_thr_tsd.c delete mode 100644 libpthread/linuxthreads_db/td_thr_validate.c delete mode 100644 libpthread/linuxthreads_db/thread_db.h delete mode 100644 libpthread/linuxthreads_db/thread_dbP.h (limited to 'libpthread') diff --git a/libpthread/linuxthreads.old/Changes b/libpthread/linuxthreads.old/Changes new file mode 100644 index 000000000..b213f36c5 --- /dev/null +++ b/libpthread/linuxthreads.old/Changes @@ -0,0 +1,85 @@ +Release 0.9: +- more ports (SH, IA-64, s390) +- many bug fixes +- timed sync object wait functions +- barrier implementation +- spinlocks implementation +- thread register on x86 +- variable stack size and position on some platforms + +Release 0.8: +(ehmm, forgot to update, don't know anymore) + +Release 0.7: +- Destructors for thread-specific data now conform to the POSIX semantics + (call destructors again if non-NULL TSD remains after a round of + destruction). +- Implemented thread-specific data as a sparse array, allows more TSD keys + and smaller thread descriptors (Ulrich Drepper). +- Added "error checking" mutexes. +- Protect against multiple sigwait() on the same signals. +- Simplified implementation of semaphores when compare_and_swap is + not available. +- Fixed bug in fork() where stdin was closed if fork() was called before + the first pthread_create(). +- Fixed bug in the gethostby*_r functions (bad result if null bytes + in addresses). +- Typos in manual pages corrected. +- First cut at a PowerPC port (not working yet, runs into problems + with gcc and with the C library). + +Release 0.6: +- Validation of thread identifiers: no more crashes when operating on + a thread that has exited (based on Pavel Krauz's ideas). +- Added fallback implementation of semaphores for the 386 and the + Sparc. +- Fixed a bug in signal handling causing false restarts of suspended + threads. +- Fixed a bug in realtime scheduling causing all threads to have + default scheduling on Ix86 with libc5. +- With realtime scheduling, unlocking a mutex now restarts the + highest priority thread waiting on the mutex, not the + first-suspended thread (Richard Neitzel). +- Timing a process now returns cumulative times for all threads, not + just times for the initial thread (suggested by Wolfram Gloger). +- Cleaned up name space (internal defs prefixed by __, weak aliases + for non-portable extensions). +- MIPS port (contributed by Ralf Baechle). + +Release 0.5: +- Signal-safe semaphores a la POSIX 1003.1b added. +- Locking bug in pthread_mutex_trylock over recursive mutexes fixed. +- Race conditions in thread cancellation fixed. +- Sparc port (contributed by Miguel de Icaza). +- Support for getpwnam_r and getpwuid_r. +- Added pthread_kill_other_threads_np to be used in conjunction with + exec*(). + +Release 0.4: +- Manual pages for all functions. +- Synchronization bug causing accumulation of zombie processes fixed. +- Race condition in pthread_cond_timedwait fixed. +- Recursive mutexes are back by popular demand. +- Partial support for realtime scheduling (initiated by Richard Neitzel). +- pthread.h cleaned up a lot: now C++ compatible, added missing "const" + qualifiers, added short documentation, put to GNU libc standards + for name space pollution (Ulrich Drepper). +- Motorola 68k port (contributed by Andreas Schwab). +- Interaction with fork(2) cleaned up a lot. + +Release 0.3: +- Thread creation and reclaimation now performed by a centralized + "thread manager" thread. +- Removed recursive mutexes to make regular mutexes more efficient. +- Now available as a shared library (contributed by Richard Henderson). +- Alpha port (contributed by Richard Henderson). +- Fixed many small discrepancies with Posix 1003.1c. +- Put under the LGPL instead of the GPL. + +Release 0.2: +- Reentrant libc functions (adapted from libc 5.3.9 by Peeter Joot) +- pthread_cond_wait did not reacquire the mutex correctly on return +- More efficient pthread_cond_broadcast + +Release 0.1: +- First public release diff --git a/libpthread/linuxthreads.old/FAQ.html b/libpthread/linuxthreads.old/FAQ.html new file mode 100644 index 000000000..21be33ec4 --- /dev/null +++ b/libpthread/linuxthreads.old/FAQ.html @@ -0,0 +1,1039 @@ + + +LinuxThreads Frequently Asked Questions + + +

LinuxThreads Frequently Asked Questions
+ (with answers)

+

[For LinuxThreads version 0.8]

+ +

+ +A. The big picture
+B. Getting more information
+C. Issues related to the C library
+D. Problems, weird behaviors, potential bugs
+E. Missing functions, wrong types, etc
+F. C++ issues
+G. Debugging LinuxThreads programs
+H. Compiling multithreaded code; errno madness
+I. X-Windows and other libraries
+J. Signals and threads
+K. Internals of LinuxThreads

+ +


+

+ +

A. The big picture

+ +

A.1: What is LinuxThreads?

+ +LinuxThreads is a Linux library for multi-threaded programming. +It implements the Posix 1003.1c API (Application Programming +Interface) for threads. It runs on any Linux system with kernel 2.0.0 +or more recent, and a suitable C library (see section C). +

+ +

A.2: What are threads?

+ +A thread is a sequential flow of control through a program. +Multi-threaded programming is, thus, a form of parallel programming +where several threads of control are executing concurrently in the +program. All threads execute in the same memory space, and can +therefore work concurrently on shared data.

+ +Multi-threaded programming differs from Unix-style multi-processing in +that all threads share the same memory space (and a few other system +resources, such as file descriptors), instead of running in their own +memory space as is the case with Unix processes.

+ +Threads are useful for two reasons. First, they allow a program to +exploit multi-processor machines: the threads can run in parallel on +several processors, allowing a single program to divide its work +between several processors, thus running faster than a single-threaded +program, which runs on only one processor at a time. Second, some +programs are best expressed as several threads of control that +communicate together, rather than as one big monolithic sequential +program. Examples include server programs, overlapping asynchronous +I/O, and graphical user interfaces.

+ +

A.3: What is POSIX 1003.1c?

+ +It's an API for multi-threaded programming standardized by IEEE as +part of the POSIX standards. Most Unix vendors have endorsed the +POSIX 1003.1c standard. Implementations of the 1003.1c API are +already available under Sun Solaris 2.5, Digital Unix 4.0, +Silicon Graphics IRIX 6, and should soon be available from other +vendors such as IBM and HP. More generally, the 1003.1c API is +replacing relatively quickly the proprietary threads library that were +developed previously under Unix, such as Mach cthreads, Solaris +threads, and IRIX sprocs. Thus, multithreaded programs using the +1003.1c API are likely to run unchanged on a wide variety of Unix +platforms.

+ +

A.4: What is the status of LinuxThreads?

+ +LinuxThreads implements almost all of Posix 1003.1c, as well as a few +extensions. The only part of LinuxThreads that does not conform yet +to Posix is signal handling (see section J). Apart +from the signal stuff, all the Posix 1003.1c base functionality, +as well as a number of optional extensions, are provided and conform +to the standard (to the best of my knowledge). +The signal stuff is hard to get right, at least without special kernel +support, and while I'm definitely looking at ways to implement the +Posix behavior for signals, this might take a long time before it's +completed.

+ +

A.5: How stable is LinuxThreads?

+ +The basic functionality (thread creation and termination, mutexes, +conditions, semaphores) is very stable. Several industrial-strength +programs, such as the AOL multithreaded Web server, use LinuxThreads +and seem quite happy about it. There used to be some rough edges in +the LinuxThreads / C library interface with libc 5, but glibc 2 +fixes all of those problems and is now the standard C library on major +Linux distributions (see section C).

+ +


+

+ +

B. Getting more information

+ +

B.1: What are good books and other sources of +information on POSIX threads?

+ +The FAQ for comp.programming.threads lists several books: +http://www.serpentine.com/~bos/threads-faq/.

+ +There are also some online tutorials. Follow the links from the +LinuxThreads web page: +http://pauillac.inria.fr/~xleroy/linuxthreads.

+ +

B.2: I'd like to be informed of future developments on +LinuxThreads. Is there a mailing list for this purpose?

+ +I post LinuxThreads-related announcements on the newsgroup +comp.os.linux.announce, +and also on the mailing list +linux-threads@magenet.com. +You can subscribe to the latter by writing +majordomo@magenet.com.

+ +

B.3: What are good places for discussing +LinuxThreads?

+ +For questions about programming with POSIX threads in general, use +the newsgroup +comp.programming.threads. +Be sure you read the +FAQ +for this group before you post.

+ +For Linux-specific questions, use +comp.os.linux.development.apps +and comp.os.linux.development.kernel. +The latter is especially appropriate for questions relative to the +interface between the kernel and LinuxThreads.

+ +

B.4: How should I report a possible bug in +LinuxThreads?

+ +If you're using glibc 2, the best way by far is to use the +glibcbug script to mail a bug report to the glibc +maintainers.

+ +If you're using an older libc, or don't have the glibcbug +script on your machine, then e-mail me directly +(Xavier.Leroy@inria.fr).

+ +In both cases, before sending the bug report, make sure that it is not +addressed already in this FAQ. Also, try to send a short program that +reproduces the weird behavior you observed.

+ +

B.5: I'd like to read the POSIX 1003.1c standard. Is +it available online?

+ +Unfortunately, no. POSIX standards are copyrighted by IEEE, and +IEEE does not distribute them freely. You can buy paper copies from +IEEE, but the price is fairly high ($120 or so). If you disagree with +this policy and you're an IEEE member, be sure to let them know.

+ +On the other hand, you probably don't want to read the standard. It's +very hard to read, written in standard-ese, and targeted to +implementors who already know threads inside-out. A good book on +POSIX threads provides the same information in a much more readable form. +I can personally recommend Dave Butenhof's book, Programming +with POSIX threads (Addison-Wesley). Butenhof was part of the +POSIX committee and also designed the Digital Unix implementations of +POSIX threads, and it shows.

+ +Another good source of information is the X/Open Group Single Unix +specification which is available both +on-line +and as a +book and CD/ROM. +That specification includes pretty much all the POSIX standards, +including 1003.1c, with some extensions and clarifications.

+ +


+

+ +

C. Issues related to the C library

+ +

C.1: Which version of the C library should I use +with LinuxThreads?

+ +The best choice by far is glibc 2, a.k.a. libc 6. It offers very good +support for multi-threading, and LinuxThreads has been closely +integrated with glibc 2. The glibc 2 distribution contains the +sources of a specially adapted version of LinuxThreads.

+ +glibc 2 comes preinstalled as the default C library on several Linux +distributions, such as RedHat 5 and up, and Debian 2. +Those distributions include the version of LinuxThreads matching +glibc 2.

+ +

C.2: My system has libc 5 preinstalled, not glibc +2. Can I still use LinuxThreads?

+ +Yes, but you're likely to run into some problems, as libc 5 only +offers minimal support for threads and contains some bugs that affect +multithreaded programs.

+ +The versions of libc 5 that work best with LinuxThreads are +libc 5.2.18 on the one hand, and libc 5.4.12 or later on the other hand. +Avoid 5.3.12 and 5.4.7: these have problems with the per-thread errno +variable.

+ +

C.3: So, should I switch to glibc 2, or stay with a +recent libc 5?

+ +I'd recommend you switch to glibc 2. Even for single-threaded +programs, glibc 2 is more solid and more standard-conformant than libc +5. And the shortcomings of libc 5 almost preclude any serious +multi-threaded programming.

+ +Switching an already installed +system from libc 5 to glibc 2 is not completely straightforward. +See the Glibc2 +HOWTO for more information. Much easier is (re-)installing a +Linux distribution based on glibc 2, such as RedHat 6.

+ +

C.4: Where can I find glibc 2 and the version of +LinuxThreads that goes with it?

+ +On prep.ai.mit.edu and its many, many mirrors around the world. +See http://www.gnu.org/order/ftp.html +for a list of mirrors.

+ +

C.5: Where can I find libc 5 and the version of +LinuxThreads that goes with it?

+ +For libc 5, see ftp://sunsite.unc.edu/pub/Linux/devel/GCC/.

+ +For the libc 5 version of LinuxThreads, see +ftp://ftp.inria.fr/INRIA/Projects/cristal/Xavier.Leroy/linuxthreads/.

+ +

C.6: How can I recompile the glibc 2 version of the +LinuxThreads sources?

+ +You must transfer the whole glibc sources, then drop the LinuxThreads +sources in the linuxthreads/ subdirectory, then recompile +glibc as a whole. There are now too many inter-dependencies between +LinuxThreads and glibc 2 to allow separate re-compilation of LinuxThreads. +

+ +

C.7: What is the correspondence between LinuxThreads +version numbers, libc version numbers, and RedHat version +numbers?

+ +Here is a summary. (Information on Linux distributions other than +RedHat are welcome.)

+ + + + + + + +
LinuxThreads C library RedHat
0.7, 0.71 (for libc 5) libc 5.x RH 4.2
0.7, 0.71 (for glibc 2) glibc 2.0.x RH 5.x
0.8 glibc 2.1.1 RH 6.0
0.8 glibc 2.1.2 not yet released
+

+ +


+

+ +

D. Problems, weird behaviors, potential bugs

+ +

D.1: When I compile LinuxThreads, I run into problems in +file libc_r/dirent.c

+ +You probably mean: +
+        libc_r/dirent.c:94: structure has no member named `dd_lock'
+
+I haven't actually seen this problem, but several users reported it. +My understanding is that something is wrong in the include files of +your Linux installation (/usr/include/*). Make sure +you're using a supported version of the libc 5 library. (See question C.2).

+ +

D.2: When I compile LinuxThreads, I run into problems with +/usr/include/sched.h: there are several occurrences of +_p that the C compiler does not understand

+ +Yes, /usr/include/sched.h that comes with libc 5.3.12 is broken. +Replace it with the sched.h file contained in the +LinuxThreads distribution. But really you should not be using libc +5.3.12 with LinuxThreads! (See question C.1.)

+ +

D.3: My program does fdopen() on a file +descriptor opened on a pipe. When I link it with LinuxThreads, +fdopen() always returns NULL!

+ +You're using one of the buggy versions of libc (5.3.12, 5.4.7., etc). +See question C.1 above.

+ +

D.4: My program creates a lot of threads, and after +a while pthread_create() no longer returns!

+ +This is known bug in the version of LinuxThreads that comes with glibc +2.1.1. An upgrade to 2.1.2 is recommended.

+ +

D.5: When I'm running a program that creates N +threads, top or ps +display N+2 processes that are running my program. What do all these +processes correspond to?

+ +Due to the general "one process per thread" model, there's one process +for the initial thread and N processes for the threads it created +using pthread_create. That leaves one process +unaccounted for. That extra process corresponds to the "thread +manager" thread, a thread created internally by LinuxThreads to handle +thread creation and thread termination. This extra thread is asleep +most of the time. + +

D.6: Scheduling seems to be very unfair when there +is strong contention on a mutex: instead of giving the mutex to each +thread in turn, it seems that it's almost always the same thread that +gets the mutex. Isn't this completely broken behavior?

+ +That behavior has mostly disappeared in recent releases of +LinuxThreads (version 0.8 and up). It was fairly common in older +releases, though. + +What happens in LinuxThreads 0.7 and before is the following: when a +thread unlocks a mutex, all other threads that were waiting on the +mutex are sent a signal which makes them runnable. However, the +kernel scheduler may or may not restart them immediately. If the +thread that unlocked the mutex tries to lock it again immediately +afterwards, it is likely that it will succeed, because the threads +haven't yet restarted. This results in an apparently very unfair +behavior, when the same thread repeatedly locks and unlocks the mutex, +while other threads can't lock the mutex.

+ +In LinuxThreads 0.8 and up, pthread_unlock restarts only +one waiting thread, and pre-assign the mutex to that thread. Hence, +if the thread that unlocked the mutex tries to lock it again +immediately, it will block until other waiting threads have had a +chance to lock and unlock the mutex. This results in much fairer +scheduling.

+ +Notice however that even the old "unfair" behavior is perfectly +acceptable with respect to the POSIX standard: for the default +scheduling policy, POSIX makes no guarantees of fairness, such as "the +thread waiting for the mutex for the longest time always acquires it +first". Properly written multithreaded code avoids that kind of heavy +contention on mutexes, and does not run into fairness problems. If +you need scheduling guarantees, you should consider using the +real-time scheduling policies SCHED_RR and +SCHED_FIFO, which have precisely defined scheduling +behaviors.

+ +

D.7: I have a simple test program with two threads +that do nothing but printf() in tight loops, and from the +printout it seems that only one thread is running, the other doesn't +print anything!

+ +Again, this behavior is characteristic of old releases of LinuxThreads +(0.7 and before); more recent versions (0.8 and up) should not exhibit +this behavior.

+ +The reason for this behavior is explained in +question D.6 above: printf() performs +locking on stdout, and thus your two threads contend very +heavily for the mutex associated with stdout. But if you +do some real work between two calls to printf(), you'll +see that scheduling becomes much smoother.

+ +

D.8: I've looked at <pthread.h> +and there seems to be a gross error in the pthread_cleanup_push +macro: it opens a block with { but does not close it! +Surely you forgot a } at the end of the macro, right? +

+ +Nope. That's the way it should be. The closing brace is provided by +the pthread_cleanup_pop macro. The POSIX standard +requires pthread_cleanup_push and +pthread_cleanup_pop to be used in matching pairs, at the +same level of brace nesting. This allows +pthread_cleanup_push to open a block in order to +stack-allocate some data structure, and +pthread_cleanup_pop to close that block. It's ugly, but +it's the standard way of implementing cleanup handlers.

+ +

D.9: I tried to use real-time threads and my program +loops like crazy and freezes the whole machine!

+ +Versions of LinuxThreads prior to 0.8 are susceptible to ``livelocks'' +(one thread loops, consuming 100% of the CPU time) in conjunction with +real-time scheduling. Since real-time threads and processes have +higher priority than normal Linux processes, all other processes on +the machine, including the shell, the X server, etc, cannot run and +the machine appears frozen.

+ +The problem is fixed in LinuxThreads 0.8.

+ +

D.10: My application needs to create thousands of +threads, or maybe even more. Can I do this with +LinuxThreads?

+ +No. You're going to run into several hard limits: + +(Other POSIX threads libraries have similar limitations, by the way.) +For all those reasons, you'd better restructure your application so +that it doesn't need more than, say, 100 threads. For instance, +in the case of a multithreaded server, instead of creating a new +thread for each connection, maintain a fixed-size pool of worker +threads that pick incoming connection requests from a queue.

+ +


+

+ +

E. Missing functions, wrong types, etc

+ +

E.1: Where is pthread_yield() ? How +comes LinuxThreads does not implement it?

+ +Because it's not part of the (final) POSIX 1003.1c standard. +Several drafts of the standard contained pthread_yield(), +but then the POSIX guys discovered it was redundant with +sched_yield() and dropped it. So, just use +sched_yield() instead. + +

E.2: I've found some type errors in +<pthread.h>. +For instance, the second argument to pthread_create() +should be a pthread_attr_t, not a +pthread_attr_t *. Also, didn't you forget to declare +pthread_attr_default?

+ +No, I didn't. What you're describing is draft 4 of the POSIX +standard, which is used in OSF DCE threads. LinuxThreads conforms to the +final standard. Even though the functions have the same names as in +draft 4 and DCE, their calling conventions are slightly different. In +particular, attributes are passed by reference, not by value, and +default attributes are denoted by the NULL pointer. Since draft 4/DCE +will eventually disappear, you'd better port your program to use the +standard interface.

+ +

E.3: I'm porting an application from Solaris and I +have to rename all thread functions from thr_blah to +pthread_blah. This is very annoying. Why did you change +all the function names?

+ +POSIX did it. The thr_* functions correspond to Solaris +threads, an older thread interface that you'll find only under +Solaris. The pthread_* functions correspond to POSIX +threads, an international standard available for many, many platforms. +Even Solaris 2.5 and later support the POSIX threads interface. So, +do yourself a favor and rewrite your code to use POSIX threads: this +way, it will run unchanged under Linux, Solaris, and quite a lot of +other platforms.

+ +

E.4: How can I suspend and resume a thread from +another thread? Solaris has the thr_suspend() and +thr_resume() functions to do that; why don't you?

+ +The POSIX standard provides no mechanism by which a thread A can +suspend the execution of another thread B, without cooperation from B. +The only way to implement a suspend/restart mechanism is to have B +check periodically some global variable for a suspend request +and then suspend itself on a condition variable, which another thread +can signal later to restart B.

+ +Notice that thr_suspend() is inherently dangerous and +prone to race conditions. For one thing, there is no control on where +the target thread stops: it can very well be stopped in the middle of +a critical section, while holding mutexes. Also, there is no +guarantee on when the target thread will actually stop. For these +reasons, you'd be much better off using mutexes and conditions +instead. The only situations that really require the ability to +suspend a thread are debuggers and some kind of garbage collectors.

+ +If you really must suspend a thread in LinuxThreads, you can send it a +SIGSTOP signal with pthread_kill. Send +SIGCONT for restarting it. +Beware, this is specific to LinuxThreads and entirely non-portable. +Indeed, a truly conforming POSIX threads implementation will stop all +threads when one thread receives the SIGSTOP signal! +One day, LinuxThreads will implement that behavior, and the +non-portable hack with SIGSTOP won't work anymore.

+ +

E.5: Does LinuxThreads implement +pthread_attr_setstacksize() and +pthread_attr_setstackaddr()?

+ +These optional functions are provided in recent versions of +LinuxThreads (0.8 and up). Earlier releases did not provide these +optional components of the POSIX standard.

+ +Even if pthread_attr_setstacksize() and +pthread_attr_setstackaddr() are now provided, we still +recommend that you do not use them unless you really have strong +reasons for doing so. The default stack allocation strategy for +LinuxThreads is nearly optimal: stacks start small (4k) and +automatically grow on demand to a fairly large limit (2M). +Moreover, there is no portable way to estimate the stack requirements +of a thread, so setting the stack size yourself makes your program +less reliable and non-portable.

+ +

E.6: LinuxThreads does not support the +PTHREAD_SCOPE_PROCESS value of the "contentionscope" +attribute. Why?

+ +With a "one-to-one" model, as in LinuxThreads (one kernel execution +context per thread), there is only one scheduler for all processes and +all threads on the system. So, there is no way to obtain the behavior of +PTHREAD_SCOPE_PROCESS. + +

E.7: LinuxThreads does not implement process-shared +mutexes, conditions, and semaphores. Why?

+ +This is another optional component of the POSIX standard. Portable +applications should test _POSIX_THREAD_PROCESS_SHARED +before using this facility. +

+The goal of this extension is to allow different processes (with +different address spaces) to synchronize through mutexes, conditions +or semaphores allocated in shared memory (either SVR4 shared memory +segments or mmap()ed files). +

+The reason why this does not work in LinuxThreads is that mutexes, +conditions, and semaphores are not self-contained: their waiting +queues contain pointers to linked lists of thread descriptors, and +these pointers are meaningful only in one address space. +

+Matt Messier and I spent a significant amount of time trying to design a +suitable mechanism for sharing waiting queues between processes. We +came up with several solutions that combined two of the following +three desirable features, but none that combines all three: +

+We concluded that kernel support is required to share mutexes, +conditions and semaphores between processes. That's one place where +Linus Torvalds's intuition that "all we need in the kernel is +clone()" fails. +

+Until suitable kernel support is available, you'd better use +traditional interprocess communications to synchronize different +processes: System V semaphores and message queues, or pipes, or sockets. +

+ +


+

+ +

F. C++ issues

+ +

F.1: Are there C++ wrappers for LinuxThreads?

+ +Douglas Schmidt's ACE library contains, among a lot of other +things, C++ wrappers for LinuxThreads and quite a number of other +thread libraries. Check out +http://www.cs.wustl.edu/~schmidt/ACE.html

+ +

F.2: I'm trying to use LinuxThreads from a C++ +program, and the compiler complains about the third argument to +pthread_create() !

+ +You're probably trying to pass a class member function or some +other C++ thing as third argument to pthread_create(). +Recall that pthread_create() is a C function, and it must +be passed a C function as third argument.

+ +

F.3: I'm trying to use LinuxThreads in conjunction +with libg++, and I'm having all sorts of trouble.

+ +>From what I understand, thread support in libg++ is completely broken, +especially with respect to locking of iostreams. H.J.Lu wrote: +
+If you want to use thread, I can only suggest egcs and glibc. You +can find egcs at +http://www.cygnus.com/egcs. +egcs has libsdtc++, which is MT safe under glibc 2. If you really +want to use the libg++, I have a libg++ add-on for egcs. +
+
+

+ +

G. Debugging LinuxThreads programs

+ +

G.1: Can I debug LinuxThreads program using gdb?

+ +Yes, but not with the stock gdb 4.17. You need a specially patched +version of gdb 4.17 developed by Eric Paire and colleages at The Open +Group, Grenoble. The patches against gdb 4.17 are available at +http://www.gr.opengroup.org/java/jdk/linux/debug.htm. +Precompiled binaries of the patched gdb are available in RedHat's RPM +format at http://odin.appliedtheory.com/.

+ +Some Linux distributions provide an already-patched version of gdb; +others don't. For instance, the gdb in RedHat 5.2 is thread-aware, +but apparently not the one in RedHat 6.0. Just ask (politely) the +makers of your Linux distributions to please make sure that they apply +the correct patches to gdb.

+ +

G.2: Does it work with post-mortem debugging?

+ +Not very well. Generally, the core file does not correspond to the +thread that crashed. The reason is that the kernel will not dump core +for a process that shares its memory with other processes, such as the +other threads of your program. So, the thread that crashes silently +disappears without generating a core file. Then, all other threads of +your program die on the same signal that killed the crashing thread. +(This is required behavior according to the POSIX standard.) The last +one that dies is no longer sharing its memory with anyone else, so the +kernel generates a core file for that thread. Unfortunately, that's +not the thread you are interested in. + +

G.3: Any other ways to debug multithreaded programs, then?

+ +Assertions and printf() are your best friends. Try to debug +sequential parts in a single-threaded program first. Then, put +printf() statements all over the place to get execution traces. +Also, check invariants often with the assert() macro. In truth, +there is no other effective way (save for a full formal proof of your +program) to track down concurrency bugs. Debuggers are not really +effective for subtle concurrency problems, because they disrupt +program execution too much.

+ +


+

+ +

H. Compiling multithreaded code; errno madness

+ +

H.1: You say all multithreaded code must be compiled +with _REENTRANT defined. What difference does it make?

+ +It affects include files in three ways: + +

+ +

H.2: Why is it so important that each thread has its +own errno variable?

+ +If all threads were to store error codes in the same, global errno +variable, then the value of errno after a system call or library +function returns would be unpredictable: between the time a system +call stores its error code in the global errno and your code inspects +errno to see which error occurred, another thread might have stored +another error code in the same errno location.

+ +

H.3: What happens if I link LinuxThreads with code +not compiled with -D_REENTRANT?

+ +Lots of trouble. If the code uses getc() or +putc(), it will perform I/O without proper interlocking +of the stdio buffers; this can cause lost output, duplicate output, or +just crash other stdio functions. If the code consults errno, it will +get back the wrong error code. The following code fragment is a +typical example: +
+        do {
+          r = read(fd, buf, n);
+          if (r == -1) {
+            if (errno == EINTR)   /* an error we can handle */
+              continue;
+            else {                /* other errors are fatal */
+              perror("read failed");
+              exit(100);
+            }
+          }
+        } while (...);
+
+Assume this code is not compiled with -D_REENTRANT, and +linked with LinuxThreads. At run-time, read() is +interrupted. Since the C library was compiled with +-D_REENTRANT, read() stores its error code +in the location pointed to by __errno_location(), which +is the thread-local errno variable. Then, the code above sees that +read() returns -1 and looks up errno. Since +_REENTRANT is not defined, the reference to errno +accesses the global errno variable, which is most likely 0. Hence the +code concludes that it cannot handle the error and stops.

+ +

H.4: With LinuxThreads, I can no longer use the signals +SIGUSR1 and SIGUSR2 in my programs! Why?

+ +The short answer is: because the Linux kernel you're using does not +support realtime signals.

+ +LinuxThreads needs two signals for its internal operation. +One is used to suspend and restart threads blocked on mutex, condition +or semaphore operations. The other is used for thread +cancellation.

+ +On ``old'' kernels (2.0 and early 2.1 kernels), there are only 32 +signals available and the kernel reserves all of them but two: +SIGUSR1 and SIGUSR2. So, LinuxThreads has +no choice but use those two signals.

+ +On recent kernels (2.2 and up), more than 32 signals are provided in +the form of realtime signals. When run on one of those kernels, +LinuxThreads uses two reserved realtime signals for its internal +operation, thus leaving SIGUSR1 and SIGUSR2 +free for user code. (This works only with glibc, not with libc 5.)

+ +

H.5: Is the stack of one thread visible from the +other threads? Can I pass a pointer into my stack to other threads? +

+ +Yes, you can -- if you're very careful. The stacks are indeed visible +from all threads in the system. Some non-POSIX thread libraries seem +to map the stacks for all threads at the same virtual addresses and +change the memory mapping when they switch from one thread to +another. But this is not the case for LinuxThreads, as it would make +context switching between threads more expensive, and at any rate +might not conform to the POSIX standard.

+ +So, you can take the address of an "auto" variable and pass it to +other threads via shared data structures. However, you need to make +absolutely sure that the function doing this will not return as long +as other threads need to access this address. It's the usual mistake +of returning the address of an "auto" variable, only made much worse +because of concurrency. It's much, much safer to systematically +heap-allocate all shared data structures.

+ +


+

+ +

I. X-Windows and other libraries

+ +

I.1: My program uses both Xlib and LinuxThreads. +It stops very early with an "Xlib: unknown 0 error" message. What +does this mean?

+ +That's a prime example of the errno problem described in question H.2. The binaries for Xlib you're using have not been +compiled with -D_REENTRANT. It happens Xlib contains a +piece of code very much like the one in question H.2. So, your Xlib fetches the error code from the +wrong errno location and concludes that an error it cannot handle +occurred.

+ +

I.2: So, what can I do to build a multithreaded X +Windows client?

+ +The best solution is to use X libraries that have been compiled with +multithreading options set. Linux distributions that come with glibc +2 as the main C library generally provide thread-safe X libraries. +At least, that seems to be the case for RedHat 5 and later.

+ +You can try to recompile yourself the X libraries with multithreading +options set. They contain optional support for multithreading; it's +just that the binaries provided by your Linux distribution were built +without this support. See the file README.Xfree3.3 in +the LinuxThreads distribution for patches and info on how to compile +thread-safe X libraries from the Xfree3.3 distribution. The Xfree3.3 +sources are readily available in most Linux distributions, e.g. as a +source RPM for RedHat. Be warned, however, that X Windows is a huge +system, and recompiling even just the libraries takes a lot of time +and disk space.

+ +Another, less involving solution is to call X functions only from the +main thread of your program. Even if all threads have their own errno +location, the main thread uses the global errno variable for its errno +location. Thus, code not compiled with -D_REENTRANT +still "sees" the right error values if it executes in the main thread +only.

+ +

This is a lot of work. Don't you have precompiled +thread-safe X libraries that you could distribute?

+ +No, I don't. Sorry. But consider installing a Linux distribution +that comes with thread-safe X libraries, such as RedHat 6.

+ +

I.3: Can I use library FOO in a multithreaded +program?

+ +Most libraries cannot be used "as is" in a multithreaded program. +For one thing, they are not necessarily thread-safe: calling +simultaneously two functions of the library from two threads might not +work, due to internal use of global variables and the like. Second, +the libraries must have been compiled with -D_REENTRANT to avoid +the errno problems explained in question H.2. +

+ +

I.4: What if I make sure that only one thread calls +functions in these libraries?

+ +This avoids problems with the library not being thread-safe. But +you're still vulnerable to errno problems. At the very least, a +recompile of the library with -D_REENTRANT is needed. +

+ +

I.5: What if I make sure that only the main thread +calls functions in these libraries?

+ +That might actually work. As explained in question I.1, +the main thread uses the global errno variable, and can therefore +execute code not compiled with -D_REENTRANT.

+ +

I.6: SVGAlib doesn't work with LinuxThreads. Why? +

+ +Because both LinuxThreads and SVGAlib use the signals +SIGUSR1 and SIGUSR2. See question H.4. +

+ + +


+

+ +

J. Signals and threads

+ +

J.1: When it comes to signals, what is shared +between threads and what isn't?

+ +Signal handlers are shared between all threads: when a thread calls +sigaction(), it sets how the signal is handled not only +for itself, but for all other threads in the program as well.

+ +On the other hand, signal masks are per-thread: each thread chooses +which signals it blocks independently of others. At thread creation +time, the newly created thread inherits the signal mask of the thread +calling pthread_create(). But afterwards, the new thread +can modify its signal mask independently of its creator thread.

+ +

J.2: When I send a SIGKILL to a +particular thread using pthread_kill, all my threads are +killed!

+ +That's how it should be. The POSIX standard mandates that all threads +should terminate when the process (i.e. the collection of all threads +running the program) receives a signal whose effect is to +terminate the process (such as SIGKILL or SIGINT +when no handler is installed on that signal). This behavior makes a +lot of sense: when you type "ctrl-C" at the keyboard, or when a thread +crashes on a division by zero or a segmentation fault, you really want +all threads to stop immediately, not just the one that caused the +segmentation violation or that got the SIGINT signal. +(This assumes default behavior for those signals; see question +J.3 if you install handlers for those signals.)

+ +If you're trying to terminate a thread without bringing the whole +process down, use pthread_cancel().

+ +

J.3: I've installed a handler on a signal. Which +thread executes the handler when the signal is received?

+ +If the signal is generated by a thread during its execution (e.g. a +thread executes a division by zero and thus generates a +SIGFPE signal), then the handler is executed by that +thread. This also applies to signals generated by +raise().

+ +If the signal is sent to a particular thread using +pthread_kill(), then that thread executes the handler.

+ +If the signal is sent via kill() or the tty interface +(e.g. by pressing ctrl-C), then the POSIX specs say that the handler +is executed by any thread in the process that does not currently block +the signal. In other terms, POSIX considers that the signal is sent +to the process (the collection of all threads) as a whole, and any +thread that is not blocking this signal can then handle it.

+ +The latter case is where LinuxThreads departs from the POSIX specs. +In LinuxThreads, there is no real notion of ``the process as a whole'': +in the kernel, each thread is really a distinct process with a +distinct PID, and signals sent to the PID of a thread can only be +handled by that thread. As long as no thread is blocking the signal, +the behavior conforms to the standard: one (unspecified) thread of the +program handles the signal. But if the thread to which PID the signal +is sent blocks the signal, and some other thread does not block the +signal, then LinuxThreads will simply queue in +that thread and execute the handler only when that thread unblocks +the signal, instead of executing the handler immediately in the other +thread that does not block the signal.

+ +This is to be viewed as a LinuxThreads bug, but I currently don't see +any way to implement the POSIX behavior without kernel support.

+ +

J.3: How shall I go about mixing signals and threads +in my program?

+ +The less you mix them, the better. Notice that all +pthread_* functions are not async-signal safe, meaning +that you should not call them from signal handlers. This +recommendation is not to be taken lightly: your program can deadlock +if you call a pthread_* function from a signal handler! +

+ +The only sensible things you can do from a signal handler is set a +global flag, or call sem_post on a semaphore, to record +the delivery of the signal. The remainder of the program can then +either poll the global flag, or use sem_wait() and +sem_trywait() on the semaphore.

+ +Another option is to do nothing in the signal handler, and dedicate +one thread (preferably the initial thread) to wait synchronously for +signals, using sigwait(), and send messages to the other +threads accordingly. + +

J.4: When one thread is blocked in +sigwait(), other threads no longer receive the signals +sigwait() is waiting for! What happens?

+ +It's an unfortunate consequence of how LinuxThreads implements +sigwait(). Basically, it installs signal handlers on all +signals waited for, in order to record which signal was received. +Since signal handlers are shared with the other threads, this +temporarily deactivates any signal handlers you might have previously +installed on these signals.

+ +Though surprising, this behavior actually seems to conform to the +POSIX standard. According to POSIX, sigwait() is +guaranteed to work as expected only if all other threads in the +program block the signals waited for (otherwise, the signals could be +delivered to other threads than the one doing sigwait(), +which would make sigwait() useless). In this particular +case, the problem described in this question does not appear.

+ +One day, sigwait() will be implemented in the kernel, +along with others POSIX 1003.1b extensions, and sigwait() +will have a more natural behavior (as well as better performances).

+ +


+

+ +

K. Internals of LinuxThreads

+ +

K.1: What is the implementation model for +LinuxThreads?

+ +LinuxThreads follows the so-called "one-to-one" model: each thread is +actually a separate process in the kernel. The kernel scheduler takes +care of scheduling the threads, just like it schedules regular +processes. The threads are created with the Linux +clone() system call, which is a generalization of +fork() allowing the new process to share the memory +space, file descriptors, and signal handlers of the parent.

+ +Advantages of the "one-to-one" model include: +

+The main disadvantage is more expensive context switches on mutex and +condition operations, which must go through the kernel. This is +mitigated by the fact that context switches in the Linux kernel are +pretty efficient.

+ +

K.2: Have you considered other implementation +models?

+ +There are basically two other models. The "many-to-one" model +relies on a user-level scheduler that context-switches between the +threads entirely in user code; viewed from the kernel, there is only +one process running. This model is completely out of the question for +me, since it does not take advantage of multiprocessors, and require +unholy magic to handle blocking I/O operations properly. There are +several user-level thread libraries available for Linux, but I found +all of them deficient in functionality, performance, and/or robustness. +

+ +The "many-to-many" model combines both kernel-level and user-level +scheduling: several kernel-level threads run concurrently, each +executing a user-level scheduler that selects between user threads. +Most commercial Unix systems (Solaris, Digital Unix, IRIX) implement +POSIX threads this way. This model combines the advantages of both +the "many-to-one" and the "one-to-one" model, and is attractive +because it avoids the worst-case behaviors of both models -- +especially on kernels where context switches are expensive, such as +Digital Unix. Unfortunately, it is pretty complex to implement, and +requires kernel support which Linux does not provide. Linus Torvalds +and other Linux kernel developers have always been pushing the +"one-to-one" model in the name of overall simplicity, and are doing a +pretty good job of making kernel-level context switches between +threads efficient. LinuxThreads is just following the general +direction they set.

+ +


+
Xavier.Leroy@inria.fr
+ + diff --git a/libpthread/linuxthreads.old/LICENSE b/libpthread/linuxthreads.old/LICENSE new file mode 100644 index 000000000..7bcca6050 --- /dev/null +++ b/libpthread/linuxthreads.old/LICENSE @@ -0,0 +1,501 @@ +GNU LIBRARY GENERAL PUBLIC LICENSE +********************************** + + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + [This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + +Preamble +======== + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it in +new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License, which was designed for utility +programs. This license, the GNU Library General Public License, +applies to certain designated libraries. This license is quite +different from the ordinary one; be sure to read it in full, and don't +assume that anything in it is the same as in the ordinary license. + + The reason we have a separate public license for some libraries is +that they blur the distinction we usually make between modifying or +adding to a program and simply using it. Linking a program with a +library, without changing the library, is in some sense simply using +the library, and is analogous to running a utility program or +application program. However, in a textual and legal sense, the linked +executable is a combined work, a derivative of the original library, +and the ordinary General Public License treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended +to permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to +achieve this as regards changes in header files, but we have achieved +it as regards changes in the actual functions of the Library.) The +hope is that this will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which + contains a notice placed by the copyright holder or other + authorized party saying it may be distributed under the terms of + this Library General Public License (also called "this License"). + Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work + which has been distributed under these terms. A "work based on the + Library" means either the Library or any derivative work under + copyright law: that is to say, a work containing the Library or a + portion of it, either verbatim or with modifications and/or + translated straightforwardly into another language. (Hereinafter, + translation is included without limitation in the term + "modification".) + + "Source code" for a work means the preferred form of the work for + making modifications to it. For a library, complete source code + means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the library. + + Activities other than copying, distribution and modification are + not covered by this License; they are outside its scope. The act + of running a program using the Library is not restricted, and + output from such a program is covered only if its contents + constitute a work based on the Library (independent of the use of + the Library in a tool for writing it). Whether that is true + depends on what the Library does and what the program that uses + the Library does. + + 1. You may copy and distribute verbatim copies of the Library's + complete source code as you receive it, in any medium, provided + that you conspicuously and appropriately publish on each copy an + appropriate copyright notice and disclaimer of warranty; keep + intact all the notices that refer to this License and to the + absence of any warranty; and distribute a copy of this License + along with the Library. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange + for a fee. + + 2. You may modify your copy or copies of the Library or any portion + of it, thus forming a work based on the Library, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a. The modified work must itself be a software library. + + b. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c. You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d. If a facility in the modified Library refers to a function or + a table of data to be supplied by an application program that + uses the facility, other than as an argument passed when the + facility is invoked, then you must make a good faith effort + to ensure that, in the event an application does not supply + such function or table, the facility still operates, and + performs whatever part of its purpose remains meaningful. + + (For example, a function in a library to compute square roots + has a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function + must be optional: if the application does not supply it, the + square root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the + Library, and can be reasonably considered independent and separate + works in themselves, then this License, and its terms, do not + apply to those sections when you distribute them as separate + works. But when you distribute the same sections as part of a + whole which is a work based on the Library, the distribution of + the whole must be on the terms of this License, whose permissions + for other licensees extend to the entire whole, and thus to each + and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Library. + + In addition, mere aggregation of another work not based on the + Library with the Library (or with a work based on the Library) on + a volume of a storage or distribution medium does not bring the + other work under the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. + To do this, you must alter all the notices that refer to this + License, so that they refer to the ordinary GNU General Public + License, version 2, instead of to this License. (If a newer + version than version 2 of the ordinary GNU General Public License + has appeared, then you can specify that version instead if you + wish.) Do not make any other change in these notices. + + Once this change is made in a given copy, it is irreversible for + that copy, so the ordinary GNU General Public License applies to + all subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of + the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or + derivative of it, under Section 2) in object code or executable + form under the terms of Sections 1 and 2 above provided that you + accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software + interchange. + + If distribution of object code is made by offering access to copy + from a designated place, then offering equivalent access to copy + the source code from the same place satisfies the requirement to + distribute the source code, even though third parties are not + compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the + Library, but is designed to work with the Library by being + compiled or linked with it, is called a "work that uses the + Library". Such a work, in isolation, is not a derivative work of + the Library, and therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library + creates an executable that is a derivative of the Library (because + it contains portions of the Library), rather than a "work that + uses the library". The executable is therefore covered by this + License. Section 6 states terms for distribution of such + executables. + + When a "work that uses the Library" uses material from a header + file that is part of the Library, the object code for the work may + be a derivative work of the Library even though the source code is + not. Whether this is true is especially significant if the work + can be linked without the Library, or if the work is itself a + library. The threshold for this to be true is not precisely + defined by law. + + If such an object file uses only numerical parameters, data + structure layouts and accessors, and small macros and small inline + functions (ten lines or less in length), then the use of the object + file is unrestricted, regardless of whether it is legally a + derivative work. (Executables containing this object code plus + portions of the Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section + 6. Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or + link a "work that uses the Library" with the Library to produce a + work containing portions of the Library, and distribute that work + under terms of your choice, provided that the terms permit + modification of the work for the customer's own use and reverse + engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered + by this License. You must supply a copy of this License. If the + work during execution displays copyright notices, you must include + the copyright notice for the Library among them, as well as a + reference directing the user to the copy of this License. Also, + you must do one of these things: + + a. Accompany the work with the complete corresponding + machine-readable source code for the Library including + whatever changes were used in the work (which must be + distributed under Sections 1 and 2 above); and, if the work + is an executable linked with the Library, with the complete + machine-readable "work that uses the Library", as object code + and/or source code, so that the user can modify the Library + and then relink to produce a modified executable containing + the modified Library. (It is understood that the user who + changes the contents of definitions files in the Library will + not necessarily be able to recompile the application to use + the modified definitions.) + + b. Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + c. If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the + above specified materials from the same place. + + d. Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the + Library" must include any data and utility programs needed for + reproducing the executable from it. However, as a special + exception, the source code distributed need not include anything + that is normally distributed (in either source or binary form) + with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that + component itself accompanies the executable. + + It may happen that this requirement contradicts the license + restrictions of other proprietary libraries that do not normally + accompany the operating system. Such a contradiction means you + cannot use both them and the Library together in an executable + that you distribute. + + 7. You may place library facilities that are a work based on the + Library side-by-side in a single library together with other + library facilities not covered by this License, and distribute + such a combined library, provided that the separate distribution + of the work based on the Library and of the other library + facilities is otherwise permitted, and provided that you do these + two things: + + a. Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b. Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same + work. + + 8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any + attempt otherwise to copy, modify, sublicense, link with, or + distribute the Library is void, and will automatically terminate + your rights under this License. However, parties who have + received copies, or rights, from you under this License will not + have their licenses terminated so long as such parties remain in + full compliance. + + 9. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify + or distribute the Library or its derivative works. These actions + are prohibited by law if you do not accept this License. + Therefore, by modifying or distributing the Library (or any work + based on the Library), you indicate your acceptance of this + License to do so, and all its terms and conditions for copying, + distributing or modifying the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the + Library subject to these terms and conditions. You may not impose + any further restrictions on the recipients' exercise of the rights + granted herein. You are not responsible for enforcing compliance + by third parties to this License. + + 11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent + issues), conditions are imposed on you (whether by court order, + agreement or otherwise) that contradict the conditions of this + License, they do not excuse you from the conditions of this + License. If you cannot distribute so as to satisfy simultaneously + your obligations under this License and any other pertinent + obligations, then as a consequence you may not distribute the + Library at all. For example, if a patent license would not permit + royalty-free redistribution of the Library by all those who + receive copies directly or indirectly through you, then the only + way you could satisfy both it and this License would be to refrain + entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable + under any particular circumstance, the balance of the section is + intended to apply, and the section as a whole is intended to apply + in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of + any such claims; this section has the sole purpose of protecting + the integrity of the free software distribution system which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is + willing to distribute software through any other system and a + licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed + to be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in + certain countries either by patents or by copyrighted interfaces, + the original copyright holder who places the Library under this + License may add an explicit geographical distribution limitation + excluding those countries, so that distribution is permitted only + in or among countries not thus excluded. In such case, this + License incorporates the limitation as if written in the body of + this License. + + 13. The Free Software Foundation may publish revised and/or new + versions of the Library General Public License from time to time. + Such new versions will be similar in spirit to the present version, + but may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Library specifies a version number of this License which applies + to it and "any later version", you have the option of following + the terms and conditions either of that version or of any later + version published by the Free Software Foundation. If the Library + does not specify a license version number, you may choose any + version ever published by the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free + Software Foundation; we sometimes make exceptions for this. Our + decision will be guided by the two goals of preserving the free + status of all derivatives of our free software and of promoting + the sharing and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE + LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT + WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE + QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE + LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY + SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY + MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE + LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, + INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR + INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU + OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY + OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries +============================================== + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of +the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should have +at least the "copyright" line and a pointer to where the full notice is +found. + + ONE LINE TO GIVE THE LIBRARY'S NAME AND AN IDEA OF WHAT IT DOES. + Copyright (C) YEAR NAME OF AUTHOR + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published + by the Free Software Foundation; either version 2 of the License, or (at + your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + + Also add information on how to contact you by electronic and paper +mail. + + You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the library + `Frob' (a library for tweaking knobs) written by James Random Hacker. + + SIGNATURE OF TY COON, 1 April 1990 + Ty Coon, President of Vice + + That's all there is to it! + diff --git a/libpthread/linuxthreads.old/Makefile b/libpthread/linuxthreads.old/Makefile new file mode 100644 index 000000000..f92f205a5 --- /dev/null +++ b/libpthread/linuxthreads.old/Makefile @@ -0,0 +1,15 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +TOPDIR=../../ + +top_srcdir=$(TOPDIR) +top_builddir=../../ +include $(top_builddir)Rules.mak +all: libs +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/linuxthreads.old/Makefile.in b/libpthread/linuxthreads.old/Makefile.in new file mode 100644 index 000000000..3aec4c562 --- /dev/null +++ b/libpthread/linuxthreads.old/Makefile.in @@ -0,0 +1,62 @@ +# Makefile for uClibc +# +# Copyright (C) 2003 Paul Mundt +# Copyright (C) 2000-2005 Erik Andersen +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +CFLAGS+=$(SSP_ALL_CFLAGS) + +# This stuff will not compile without at least -O1 +CFLAGS:=$(CFLAGS:-O0=-O1) + +LDFLAGS:=$(LDFLAGS_NOSTRIP) + +ifeq ($(UCLIBC_CTOR_DTOR),y) +SHARED_START_FILES:=$(top_builddir)lib/crti.o $(LIBGCC_DIR)crtbeginS.o +SHARED_END_FILES:=$(LIBGCC_DIR)crtendS.o $(top_builddir)lib/crtn.o +endif + +ifeq ($(PTHREADS_DEBUG_SUPPORT),y) +STRIP_FLAGS:=-X --strip-debug -R .note -R .comment +endif + +DOMULTI=n + +LIB_NAME:=libpthread + +libpthread_DIR:=$(top_srcdir)libpthread/linuxthreads.old +libpthread_OUT:=$(top_builddir)libpthread/linuxthreads.old + +ARCH_CFLAGS:=$(CFLAGS) +-include $(libpthread_DIR)/sysdeps/$(TARGET_ARCH)/Makefile.arch +CFLAGS:=$(ARCH_CFLAGS) + +libpthread_SRC:=$(wildcard $(libpthread_DIR)/*.c) +ifneq ($(UCLIBC_HAS_XLOCALE),y) +libpthread_SRC:=$(filter-out $(libpthread_DIR)/locale.c,$(libpthread_SRC)) +endif + +ifneq ($(DOMULTI),n) +libpthread_NO_MULTI:=manager.c pt-machine.c +libpthread_SRC:=$(filter-out $(patsubst %.c,$(libpthread_DIR)/%.c,$(libpthread_NO_MULTI)),$(libpthread_SRC)) +endif + +# remove generic sources, if arch specific version is present +ifneq ($(strip $(libpthread_ARCH_SRC)),) +libpthread_SRC:=$(filter-out $(patsubst %.c,$(libpthread_DIR)/%.c,$(notdir $(libpthread_ARCH_SRC))),$(libpthread_SRC)) +endif + +libpthread_OBJ:=$(patsubst $(libpthread_DIR)/%.c,$(libpthread_OUT)/%.o,$(libpthread_SRC)) + +libpthread-a-$(UCLIBC_HAS_THREADS)+=$(libpthread_OBJ) +libpthread-so-$(UCLIBC_HAS_THREADS)+=$(libpthread_OBJ:.o=.os) + +libpthread-multi-$(UCLIBC_HAS_THREADS)+=$(libpthread_SRC) +libpthread-nomulti-$(UCLIBC_HAS_THREADS)+=$(patsubst %.c,$(libpthread_OUT)/%.o,$(libpthread_NO_MULTI)) + +objclean-y+=libpthread_clean + +lib-a-$(UCLIBC_HAS_THREADS)+=$(top_builddir)lib/libpthread.a +lib-so-$(UCLIBC_HAS_THREADS)+=$(top_builddir)lib/libpthread.so diff --git a/libpthread/linuxthreads.old/README b/libpthread/linuxthreads.old/README new file mode 100644 index 000000000..955bd59e7 --- /dev/null +++ b/libpthread/linuxthreads.old/README @@ -0,0 +1,166 @@ + Linuxthreads - POSIX 1003.1c kernel threads for Linux + + Copyright 1996, 1997 Xavier Leroy (Xavier.Leroy@inria.fr) + + +DESCRIPTION: + +This is release 0.7 (late beta) of LinuxThreads, a BiCapitalized +implementation of the Posix 1003.1c "pthread" interface for Linux. + +LinuxThreads provides kernel-level threads: each thread is a separate +Unix process, sharing its address space with the other threads through +the new system call clone(). Scheduling between threads is handled by +the kernel scheduler, just like scheduling between Unix processes. + + +REQUIREMENTS: + +- Linux version 2.0 and up (requires the new clone() system call + and the new realtime scheduler). + +- For Intel platforms: libc 5.2.18 or later is required. + 5.2.18 or 5.4.12 or later are recommended; + 5.3.12 and 5.4.7 have problems (see the FAQ.html file for more info). + +- Also supports glibc 2 (a.k.a. libc 6), which actually comes with + a specially-adapted version of this library. + +- Currently supports Intel, Alpha, Sparc, Motorola 68k, ARM and MIPS + platforms. + +- Multiprocessors are supported. + + +INSTALLATION: + +- Edit the Makefile, set the variables in the "Configuration" section. + +- Do "make". + +- Do "make install". + + +USING LINUXTHREADS: + + gcc -D_REENTRANT ... -lpthread + +A complete set of manual pages is included. Also see the subdirectory +Examples/ for some sample programs. + + +STATUS: + +- All functions in the Posix 1003.1c base interface implemented. + Also supports priority scheduling. + +- For users of libc 5 (H.J.Lu's libc), a number of C library functions + are reimplemented or wrapped to make them thread-safe, including: + * malloc functions + * stdio functions (define _REENTRANT before including ) + * per-thread errno variable (define _REENTRANT before including ) + * directory reading functions (opendir(), etc) + * sleep() + * gmtime(), localtime() + + New library functions provided: + * flockfile(), funlockfile(), ftrylockfile() + * reentrant versions of network database functions (gethostbyname_r(), etc) + and password functions (getpwnam_r(), etc). + +- libc 6 (glibc 2) provides much better thread support than libc 5, + and comes with a specially-adapted version of LinuxThreads. + For serious multithreaded programming, you should consider switching + to glibc 2. It is available from ftp.gnu.org:/pub/gnu and its mirrors. + + +WARNING: + +Many existing libraries are not compatible with LinuxThreads, +either because they are not inherently thread-safe, or because they +have not been compiled with the -D_REENTRANT. For more info, see the +FAQ.html file in this directory. + +A prime example of the latter is Xlib. If you link it with +LinuxThreads, you'll probably get an "unknown 0 error" very +early. This is just a consequence of the Xlib binaries using the +global variable "errno" to fetch error codes, while LinuxThreads and +the C library use the per-thread "errno" location. + +See the file README.Xfree3.3 for info on how to compile the Xfree 3.3 +libraries to make them compatible with LinuxThreads. + + +KNOWN BUGS AND LIMITATIONS: + +- Threads share pretty much everything they should share according + to the standard: memory space, file descriptors, signal handlers, + current working directory, etc. One thing that they do not share + is their pid's and parent pid's. According to the standard, they + should have the same, but that's one thing we cannot achieve + in this implementation (until the CLONE_PID flag to clone() becomes + usable). + +- The current implementation uses the two signals SIGUSR1 and SIGUSR2, + so user-level code cannot employ them. Ideally, there should be two + signals reserved for this library. One signal is used for restarting + threads blocked on mutexes or conditions; the other is for thread + cancellation. + + *** This is not anymore true when the application runs on a kernel + newer than approximately 2.1.60. + +- The stacks for the threads are allocated high in the memory space, + below the stack of the initial process, and spaced 2M apart. + Stacks are allocated with the "grow on demand" flag, so they don't + use much virtual space initially (4k, currently), but can grow + up to 2M if needed. + + Reserving such a large address space for each thread means that, + on a 32-bit architecture, no more than about 1000 threads can + coexist (assuming a 2Gb address space for user processes), + but this is reasonable, since each thread uses up one entry in the + kernel's process table, which is usually limited to 512 processes. + + Another potential problem of the "grow on demand" scheme is that + nothing prevents the user from mmap'ing something in the 2M address + window reserved for a thread stack, possibly causing later extensions of + that stack to fail. Mapping at fixed addresses should be avoided + when using this library. + +- Signal handling does not fully conform to the Posix standard, + due to the fact that threads are here distinct processes that can be + sent signals individually, so there's no notion of sending a signal + to "the" process (the collection of all threads). + More precisely, here is a summary of the standard requirements + and how they are met by the implementation: + + 1- Synchronous signals (generated by the thread execution, e.g. SIGFPE) + are delivered to the thread that raised them. + (OK.) + + 2- A fatal asynchronous signal terminates all threads in the process. + (OK. The thread manager notices when a thread dies on a signal + and kills all other threads with the same signal.) + + 3- An asynchronous signal will be delivered to one of the threads + of the program which does not block the signal (it is unspecified + which). + (No, the signal is delivered to the thread it's been sent to, + based on the pid of the thread. If that thread is currently + blocking the signal, the signal remains pending.) + + 4- The signal will be delivered to at most one thread. + (OK, except for signals generated from the terminal or sent to + the process group, which will be delivered to all threads.) + +- The current implementation of the MIPS support assumes a MIPS ISA II + processor or better. These processors support atomic operations by + ll/sc instructions. Older R2000/R3000 series processors are not + supported yet; support for these will have higher overhead. + +- The current implementation of the ARM support assumes that the SWP + (atomic swap register with memory) instruction is available. This is + the case for all processors except for the ARM1 and ARM2. On StrongARM, + the SWP instruction does not bypass the cache, so multi-processor support + will be more troublesome. diff --git a/libpthread/linuxthreads.old/attr.c b/libpthread/linuxthreads.old/attr.c new file mode 100644 index 000000000..4432a04d1 --- /dev/null +++ b/libpthread/linuxthreads.old/attr.c @@ -0,0 +1,214 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* changed for uClibc */ +#define __sched_get_priority_min sched_get_priority_min +#define __sched_get_priority_max sched_get_priority_max + +/* Handling of thread attributes */ + +#include +#include +#include +#include +#include "pthread.h" +#include "internals.h" + +extern int __getpagesize(void); + +/* NOTE: With uClibc I don't think we need this versioning stuff. + * Therefore, define the function pthread_attr_init() here using + * a strong symbol. */ + +//int __pthread_attr_init_2_1(pthread_attr_t *attr) +int pthread_attr_init(pthread_attr_t *attr) +{ + size_t ps = __getpagesize (); + + attr->__detachstate = PTHREAD_CREATE_JOINABLE; + attr->__schedpolicy = SCHED_OTHER; + attr->__schedparam.sched_priority = 0; + attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; + attr->__scope = PTHREAD_SCOPE_SYSTEM; + attr->__guardsize = ps; + attr->__stackaddr = NULL; + attr->__stackaddr_set = 0; + attr->__stacksize = STACK_SIZE - ps; + return 0; +} + +/* uClibc: leave out this for now. */ +#if DO_PTHREAD_VERSIONING_WITH_UCLIBC +#if defined __HAVE_ELF__ && defined __PIC__ && defined DO_VERSIONING +default_symbol_version (__pthread_attr_init_2_1, pthread_attr_init, GLIBC_2.1); + +int __pthread_attr_init_2_0(pthread_attr_t *attr) +{ + attr->__detachstate = PTHREAD_CREATE_JOINABLE; + attr->__schedpolicy = SCHED_OTHER; + attr->__schedparam.sched_priority = 0; + attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; + attr->__scope = PTHREAD_SCOPE_SYSTEM; + return 0; +} +symbol_version (__pthread_attr_init_2_0, pthread_attr_init, GLIBC_2.0); +#else +strong_alias (__pthread_attr_init_2_1, pthread_attr_init) +#endif +#endif /* DO_PTHREAD_VERSIONING_WITH_UCLIBC */ + +int pthread_attr_destroy(pthread_attr_t *attr) +{ + return 0; +} + +int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + if (detachstate < PTHREAD_CREATE_JOINABLE || + detachstate > PTHREAD_CREATE_DETACHED) + return EINVAL; + attr->__detachstate = detachstate; + return 0; +} + +int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) +{ + *detachstate = attr->__detachstate; + return 0; +} + +int pthread_attr_setschedparam(pthread_attr_t *attr, + const struct sched_param *param) +{ + int max_prio = __sched_get_priority_max(attr->__schedpolicy); + int min_prio = __sched_get_priority_min(attr->__schedpolicy); + + if (param->sched_priority < min_prio || param->sched_priority > max_prio) + return EINVAL; + memcpy (&attr->__schedparam, param, sizeof (struct sched_param)); + return 0; +} + +int pthread_attr_getschedparam(const pthread_attr_t *attr, + struct sched_param *param) +{ + memcpy (param, &attr->__schedparam, sizeof (struct sched_param)); + return 0; +} + +int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) +{ + if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR) + return EINVAL; + attr->__schedpolicy = policy; + return 0; +} + +int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) +{ + *policy = attr->__schedpolicy; + return 0; +} + +int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) +{ + if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED) + return EINVAL; + attr->__inheritsched = inherit; + return 0; +} + +int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) +{ + *inherit = attr->__inheritsched; + return 0; +} + +int pthread_attr_setscope(pthread_attr_t *attr, int scope) +{ + switch (scope) { + case PTHREAD_SCOPE_SYSTEM: + attr->__scope = scope; + return 0; + case PTHREAD_SCOPE_PROCESS: + return ENOTSUP; + default: + return EINVAL; + } +} + +int pthread_attr_getscope(const pthread_attr_t *attr, int *scope) +{ + *scope = attr->__scope; + return 0; +} + +int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) +{ + size_t ps = __getpagesize (); + + /* First round up the guard size. */ + guardsize = roundup (guardsize, ps); + + /* The guard size must not be larger than the stack itself */ + if (guardsize >= attr->__stacksize) return EINVAL; + + attr->__guardsize = guardsize; + + return 0; +} +weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize) + +int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) +{ + *guardsize = attr->__guardsize; + return 0; +} +weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize) + +int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) +{ + attr->__stackaddr = stackaddr; + attr->__stackaddr_set = 1; + return 0; +} +weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr) + +int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) +{ + /* XXX This function has a stupid definition. The standard specifies + no error value but what is if no stack address was set? We simply + return the value we have in the member. */ + *stackaddr = attr->__stackaddr; + return 0; +} +weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr) + +int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ + /* We don't accept value smaller than PTHREAD_STACK_MIN. */ + if (stacksize < PTHREAD_STACK_MIN) + return EINVAL; + + attr->__stacksize = stacksize; + return 0; +} +weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize) + +int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) +{ + *stacksize = attr->__stacksize; + return 0; +} +weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize) diff --git a/libpthread/linuxthreads.old/cancel.c b/libpthread/linuxthreads.old/cancel.c new file mode 100644 index 000000000..1356348a7 --- /dev/null +++ b/libpthread/linuxthreads.old/cancel.c @@ -0,0 +1,184 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Thread cancellation */ + +#define __FORCE_GLIBC +#include +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#ifdef __UCLIBC_HAS_RPC__ +#include +extern void __rpc_thread_destroy(void); +#endif + + +int pthread_setcancelstate(int state, int * oldstate) +{ + pthread_descr self = thread_self(); + if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE) + return EINVAL; + if (oldstate != NULL) *oldstate = THREAD_GETMEM(self, p_cancelstate); + THREAD_SETMEM(self, p_cancelstate, state); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) + pthread_exit(PTHREAD_CANCELED); + return 0; +} + +int pthread_setcanceltype(int type, int * oldtype) +{ + pthread_descr self = thread_self(); + if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS) + return EINVAL; + if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype); + THREAD_SETMEM(self, p_canceltype, type); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) + pthread_exit(PTHREAD_CANCELED); + return 0; +} + +int pthread_cancel(pthread_t thread) +{ + pthread_handle handle = thread_handle(thread); + int pid; + int dorestart = 0; + pthread_descr th; + pthread_extricate_if *pextricate; + + __pthread_lock(&handle->h_lock, NULL); + if (invalid_handle(handle, thread)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + + th = handle->h_descr; + + if (th->p_canceled) { + __pthread_unlock(&handle->h_lock); + return 0; + } + + pextricate = th->p_extricate; + th->p_canceled = 1; + pid = th->p_pid; + + /* If the thread has registered an extrication interface, then + invoke the interface. If it returns 1, then we succeeded in + dequeuing the thread from whatever waiting object it was enqueued + with. In that case, it is our responsibility to wake it up. + And also to set the p_woken_by_cancel flag so the woken thread + can tell that it was woken by cancellation. */ + + if (pextricate != NULL) { + dorestart = pextricate->pu_extricate_func(pextricate->pu_object, th); + th->p_woken_by_cancel = dorestart; + } + + __pthread_unlock(&handle->h_lock); + + /* If the thread has suspended or is about to, then we unblock it by + issuing a restart, instead of a cancel signal. Otherwise we send + the cancel signal to unblock the thread from a cancellation point, + or to initiate asynchronous cancellation. The restart is needed so + we have proper accounting of restarts; suspend decrements the thread's + resume count, and restart() increments it. This also means that suspend's + handling of the cancel signal is obsolete. */ + + if (dorestart) + restart(th); + else + kill(pid, __pthread_sig_cancel); + + return 0; +} + +void pthread_testcancel(void) +{ + pthread_descr self = thread_self(); + if (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) + pthread_exit(PTHREAD_CANCELED); +} + +void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer, + void (*routine)(void *), void * arg) +{ + pthread_descr self = thread_self(); + buffer->__routine = routine; + buffer->__arg = arg; + buffer->__prev = THREAD_GETMEM(self, p_cleanup); + THREAD_SETMEM(self, p_cleanup, buffer); +} + +void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer, + int execute) +{ + pthread_descr self = thread_self(); + if (execute) buffer->__routine(buffer->__arg); + THREAD_SETMEM(self, p_cleanup, buffer->__prev); +} + +void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer, + void (*routine)(void *), void * arg) +{ + pthread_descr self = thread_self(); + buffer->__routine = routine; + buffer->__arg = arg; + buffer->__canceltype = THREAD_GETMEM(self, p_canceltype); + buffer->__prev = THREAD_GETMEM(self, p_cleanup); + THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED); + THREAD_SETMEM(self, p_cleanup, buffer); +} + +void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer, + int execute) +{ + pthread_descr self = thread_self(); + if (execute) buffer->__routine(buffer->__arg); + THREAD_SETMEM(self, p_cleanup, buffer->__prev); + THREAD_SETMEM(self, p_canceltype, buffer->__canceltype); + if (THREAD_GETMEM(self, p_canceled) && + THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && + THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) + pthread_exit(PTHREAD_CANCELED); +} + +void __pthread_perform_cleanup(void) +{ + pthread_descr self = thread_self(); + struct _pthread_cleanup_buffer * c; + for (c = THREAD_GETMEM(self, p_cleanup); c != NULL; c = c->__prev) + c->__routine(c->__arg); + +#ifdef __UCLIBC_HAS_RPC__ + /* And the TSD which needs special help. */ + if (THREAD_GETMEM(self, p_libc_specific[_LIBC_TSD_KEY_RPC_VARS]) != NULL) + __rpc_thread_destroy (); +#endif +} + +#ifndef __PIC__ +/* We need a hook to force the cancelation wrappers to be linked in when + static libpthread is used. */ +extern const int __pthread_provide_wrappers; +static const int * const __pthread_require_wrappers = + &__pthread_provide_wrappers; +#endif diff --git a/libpthread/linuxthreads.old/condvar.c b/libpthread/linuxthreads.old/condvar.c new file mode 100644 index 000000000..f9c46a331 --- /dev/null +++ b/libpthread/linuxthreads.old/condvar.c @@ -0,0 +1,296 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* and Pavel Krauz (krauz@fsid.cvut.cz). */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Condition variables */ + +#include +#include +#include +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "queue.h" +#include "restart.h" + +int pthread_cond_init(pthread_cond_t *cond, + const pthread_condattr_t *cond_attr) +{ + __pthread_init_lock(&cond->__c_lock); + cond->__c_waiting = NULL; + return 0; +} + +int pthread_cond_destroy(pthread_cond_t *cond) +{ + if (cond->__c_waiting != NULL) return EBUSY; + return 0; +} + +/* Function called by pthread_cancel to remove the thread from + waiting on a condition variable queue. */ + +static int cond_extricate_func(void *obj, pthread_descr th) +{ + volatile pthread_descr self = thread_self(); + pthread_cond_t *cond = obj; + int did_remove = 0; + + __pthread_lock(&cond->__c_lock, self); + did_remove = remove_from_queue(&cond->__c_waiting, th); + __pthread_unlock(&cond->__c_lock); + + return did_remove; +} + +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + volatile pthread_descr self = thread_self(); + pthread_extricate_if extr; + int already_canceled = 0; + int spurious_wakeup_count; + + /* Check whether the mutex is locked and owned by this thread. */ + if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP + && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP + && mutex->__m_owner != self) + return EINVAL; + + /* Set up extrication interface */ + extr.pu_object = cond; + extr.pu_extricate_func = cond_extricate_func; + + /* Register extrication interface */ + THREAD_SETMEM(self, p_condvar_avail, 0); + __pthread_set_own_extricate_if(self, &extr); + + /* Atomically enqueue thread for waiting, but only if it is not + canceled. If the thread is canceled, then it will fall through the + suspend call below, and then call pthread_exit without + having to worry about whether it is still on the condition variable queue. + This depends on pthread_cancel setting p_canceled before calling the + extricate function. */ + + __pthread_lock(&cond->__c_lock, self); + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + enqueue(&cond->__c_waiting, self); + else + already_canceled = 1; + __pthread_unlock(&cond->__c_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + pthread_exit(PTHREAD_CANCELED); + } + + pthread_mutex_unlock(mutex); + + spurious_wakeup_count = 0; + while (1) + { + suspend(self); + if (THREAD_GETMEM(self, p_condvar_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + + __pthread_set_own_extricate_if(self, 0); + + /* Check for cancellation again, to provide correct cancellation + point behavior */ + + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + pthread_mutex_lock(mutex); + pthread_exit(PTHREAD_CANCELED); + } + + /* Put back any resumes we caught that don't belong to us. */ + while (spurious_wakeup_count--) + restart(self); + + pthread_mutex_lock(mutex); + return 0; +} + +static int +pthread_cond_timedwait_relative(pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec * abstime) +{ + volatile pthread_descr self = thread_self(); + int already_canceled = 0; + pthread_extricate_if extr; + int spurious_wakeup_count; + + /* Check whether the mutex is locked and owned by this thread. */ + if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP + && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP + && mutex->__m_owner != self) + return EINVAL; + + /* Set up extrication interface */ + extr.pu_object = cond; + extr.pu_extricate_func = cond_extricate_func; + + /* Register extrication interface */ + THREAD_SETMEM(self, p_condvar_avail, 0); + __pthread_set_own_extricate_if(self, &extr); + + /* Enqueue to wait on the condition and check for cancellation. */ + __pthread_lock(&cond->__c_lock, self); + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + enqueue(&cond->__c_waiting, self); + else + already_canceled = 1; + __pthread_unlock(&cond->__c_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + pthread_exit(PTHREAD_CANCELED); + } + + pthread_mutex_unlock(mutex); + + spurious_wakeup_count = 0; + while (1) + { + if (!timedsuspend(self, abstime)) { + int was_on_queue; + + /* __pthread_lock will queue back any spurious restarts that + may happen to it. */ + + __pthread_lock(&cond->__c_lock, self); + was_on_queue = remove_from_queue(&cond->__c_waiting, self); + __pthread_unlock(&cond->__c_lock); + + if (was_on_queue) { + __pthread_set_own_extricate_if(self, 0); + pthread_mutex_lock(mutex); + return ETIMEDOUT; + } + + /* Eat the outstanding restart() from the signaller */ + suspend(self); + } + + if (THREAD_GETMEM(self, p_condvar_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + + __pthread_set_own_extricate_if(self, 0); + + /* The remaining logic is the same as in other cancellable waits, + such as pthread_join sem_wait or pthread_cond wait. */ + + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + pthread_mutex_lock(mutex); + pthread_exit(PTHREAD_CANCELED); + } + + /* Put back any resumes we caught that don't belong to us. */ + while (spurious_wakeup_count--) + restart(self); + + pthread_mutex_lock(mutex); + return 0; +} + +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec * abstime) +{ + /* Indirect call through pointer! */ + return pthread_cond_timedwait_relative(cond, mutex, abstime); +} + +int pthread_cond_signal(pthread_cond_t *cond) +{ + pthread_descr th; + + __pthread_lock(&cond->__c_lock, NULL); + th = dequeue(&cond->__c_waiting); + __pthread_unlock(&cond->__c_lock); + if (th != NULL) { + th->p_condvar_avail = 1; + WRITE_MEMORY_BARRIER(); + restart(th); + } + return 0; +} + +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + pthread_descr tosignal, th; + + __pthread_lock(&cond->__c_lock, NULL); + /* Copy the current state of the waiting queue and empty it */ + tosignal = cond->__c_waiting; + cond->__c_waiting = NULL; + __pthread_unlock(&cond->__c_lock); + /* Now signal each process in the queue */ + while ((th = dequeue(&tosignal)) != NULL) { + th->p_condvar_avail = 1; + WRITE_MEMORY_BARRIER(); + restart(th); + } + return 0; +} + +int pthread_condattr_init(pthread_condattr_t *attr) +{ + return 0; +} + +int pthread_condattr_destroy(pthread_condattr_t *attr) +{ + return 0; +} + +int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) +{ + *pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} + +int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + /* For now it is not possible to shared a conditional variable. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; + + return 0; +} diff --git a/libpthread/linuxthreads.old/debug.h b/libpthread/linuxthreads.old/debug.h new file mode 100644 index 000000000..a2ac5113a --- /dev/null +++ b/libpthread/linuxthreads.old/debug.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** NAME: +** debug.h +** +** DESCRIPTION: +** This header file defines the debug macros used in pthreads. To turn +** debugging on, add -DDEBUG_PT to CFLAGS. It was added to the original +** distribution of linuxthreads. +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU Library General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Library General Public License for more details. +** +****************************************************************************/ + +#ifndef _PT_DEBUG_H +#define _PT_DEBUG_H + +#include + +#ifdef __DODEBUG_PT__ +# define DEBUG_PT +#endif + +/* include asserts for now */ +#define DO_ASSERT + +/* define the PDEBUG macro here */ +#undef PDEBUG +#ifdef DEBUG_PT +# define PDEBUG(fmt, args...) __pthread_message("%s: " fmt, __FUNCTION__, ## args) +#else +# define PDEBUG(fmt, args...) /* debug switched off */ +#endif + +/* nothing; placeholder to disable a PDEBUG message but don't delete it */ +#undef PDEBUGG +#define PDEBUGG(fmt, args...) + +/* Define ASSERT to stop/warn. Should be void in production code */ +#undef ASSERT +#ifdef DO_ASSERT +# define ASSERT(x) if (!(x)) fprintf(stderr, "pt: assertion failed in %s:%i.\n",\ + __FILE__, __LINE__) +#else +# define ASSERT(x) +#endif + +#endif /* _PT_DEBUG_H */ diff --git a/libpthread/linuxthreads.old/errno.c b/libpthread/linuxthreads.old/errno.c new file mode 100644 index 000000000..f5778f98a --- /dev/null +++ b/libpthread/linuxthreads.old/errno.c @@ -0,0 +1,37 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Define the location of errno for the remainder of the C library */ + +#define __FORCE_GLIBC +#include +#include +#include +#include "pthread.h" +#include "internals.h" +#include + +int * +__errno_location (void) +{ + pthread_descr self = thread_self(); + return THREAD_GETMEM (self, p_errnop); +} + +int * +__h_errno_location (void) +{ + pthread_descr self = thread_self(); + return THREAD_GETMEM (self, p_h_errnop); +} diff --git a/libpthread/linuxthreads.old/events.c b/libpthread/linuxthreads.old/events.c new file mode 100644 index 000000000..a4bf1f898 --- /dev/null +++ b/libpthread/linuxthreads.old/events.c @@ -0,0 +1,37 @@ +/* Event functions used while debugging. + Copyright (C) 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* The functions contained here do nothing, they just return. */ + +#include "internals.h" + +void +__linuxthreads_create_event (void) +{ +} + +void +__linuxthreads_death_event (void) +{ +} + +void +__linuxthreads_reap_event (void) +{ +} diff --git a/libpthread/linuxthreads.old/internals.h b/libpthread/linuxthreads.old/internals.h new file mode 100644 index 000000000..4b3396aee --- /dev/null +++ b/libpthread/linuxthreads.old/internals.h @@ -0,0 +1,518 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#ifndef _INTERNALS_H +#define _INTERNALS_H 1 + +/* Internal data structures */ + +/* Includes */ + +#include /* for _LIBC_TSD_KEY_N */ +#include +#include +#include +#include +#include +#include "pt-machine.h" +#include "semaphore.h" +#include "../linuxthreads.old_db/thread_dbP.h" +#ifdef __UCLIBC_HAS_XLOCALE__ +#include +#endif /* __UCLIBC_HAS_XLOCALE__ */ + +/* Use a funky version in a probably vein attempt at preventing gdb + * from dlopen()'ing glibc's libthread_db library... */ +#define STRINGIFY(s) STRINGIFY2 (s) +#define STRINGIFY2(s) #s +#define VERSION STRINGIFY(__UCLIBC_MAJOR__) "." STRINGIFY(__UCLIBC_MINOR__) "." STRINGIFY(__UCLIBC_SUBLEVEL__) + +#ifndef THREAD_GETMEM +# define THREAD_GETMEM(descr, member) descr->member +#endif +#ifndef THREAD_GETMEM_NC +# define THREAD_GETMEM_NC(descr, member) descr->member +#endif +#ifndef THREAD_SETMEM +# define THREAD_SETMEM(descr, member, value) descr->member = (value) +#endif +#ifndef THREAD_SETMEM_NC +# define THREAD_SETMEM_NC(descr, member, value) descr->member = (value) +#endif + +/* Arguments passed to thread creation routine */ + +struct pthread_start_args { + void * (*start_routine)(void *); /* function to run */ + void * arg; /* its argument */ + sigset_t mask; /* initial signal mask for thread */ + int schedpolicy; /* initial scheduling policy (if any) */ + struct sched_param schedparam; /* initial scheduling parameters (if any) */ +}; + + +/* We keep thread specific data in a special data structure, a two-level + array. The top-level array contains pointers to dynamically allocated + arrays of a certain number of data pointers. So we can implement a + sparse array. Each dynamic second-level array has + PTHREAD_KEY_2NDLEVEL_SIZE + entries. This value shouldn't be too large. */ +#define PTHREAD_KEY_2NDLEVEL_SIZE 32 + +/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE + keys in each subarray. */ +#define PTHREAD_KEY_1STLEVEL_SIZE \ + ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \ + / PTHREAD_KEY_2NDLEVEL_SIZE) + +typedef void (*destr_function)(void *); + +struct pthread_key_struct { + int in_use; /* already allocated? */ + destr_function destr; /* destruction routine */ +}; + + +#define PTHREAD_START_ARGS_INITIALIZER { NULL, NULL, {{0, }}, 0, { 0 } } + +/* The type of thread descriptors */ + +typedef struct _pthread_descr_struct * pthread_descr; + +/* Callback interface for removing the thread from waiting on an + object if it is cancelled while waiting or about to wait. + This hold a pointer to the object, and a pointer to a function + which ``extricates'' the thread from its enqueued state. + The function takes two arguments: pointer to the wait object, + and a pointer to the thread. It returns 1 if an extrication + actually occured, and hence the thread must also be signalled. + It returns 0 if the thread had already been extricated. */ + +typedef struct _pthread_extricate_struct { + void *pu_object; + int (*pu_extricate_func)(void *, pthread_descr); +} pthread_extricate_if; + +/* Atomic counter made possible by compare_and_swap */ + +struct pthread_atomic { + long p_count; + int p_spinlock; +}; + +/* Context info for read write locks. The pthread_rwlock_info structure + is information about a lock that has been read-locked by the thread + in whose list this structure appears. The pthread_rwlock_context + is embedded in the thread context and contains a pointer to the + head of the list of lock info structures, as well as a count of + read locks that are untracked, because no info structure could be + allocated for them. */ + +struct _pthread_rwlock_t; + +typedef struct _pthread_rwlock_info { + struct _pthread_rwlock_info *pr_next; + struct _pthread_rwlock_t *pr_lock; + int pr_lock_count; +} pthread_readlock_info; + +struct _pthread_descr_struct { + pthread_descr p_nextlive, p_prevlive; + /* Double chaining of active threads */ + pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */ + pthread_descr p_nextlock; /* can be on a queue and waiting on a lock */ + pthread_t p_tid; /* Thread identifier */ + int p_pid; /* PID of Unix process */ + int p_priority; /* Thread priority (== 0 if not realtime) */ + struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */ + int p_signal; /* last signal received */ + sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */ + sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */ + char p_terminated; /* true if terminated e.g. by pthread_exit */ + char p_detached; /* true if detached */ + char p_exited; /* true if the assoc. process terminated */ + void * p_retval; /* placeholder for return value */ + int p_retcode; /* placeholder for return code */ + pthread_descr p_joining; /* thread joining on that thread or NULL */ + struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */ + char p_cancelstate; /* cancellation state */ + char p_canceltype; /* cancellation type (deferred/async) */ + char p_canceled; /* cancellation request pending */ + int * p_errnop; /* pointer to used errno variable */ + int p_errno; /* error returned by last system call */ + int * p_h_errnop; /* pointer to used h_errno variable */ + int p_h_errno; /* error returned by last netdb function */ + char * p_in_sighandler; /* stack address of sighandler, or NULL */ + char p_sigwaiting; /* true if a sigwait() is in progress */ + struct pthread_start_args p_start_args; /* arguments for thread creation */ + void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */ + void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */ + int p_userstack; /* nonzero if the user provided the stack */ + void *p_guardaddr; /* address of guard area or NULL */ + size_t p_guardsize; /* size of guard area */ + pthread_descr p_self; /* Pointer to this structure */ + int p_nr; /* Index of descriptor in __pthread_handles */ + int p_report_events; /* Nonzero if events must be reported. */ + td_eventbuf_t p_eventbuf; /* Data for event. */ + struct pthread_atomic p_resume_count; /* number of times restart() was + called on thread */ + char p_woken_by_cancel; /* cancellation performed wakeup */ + char p_condvar_avail; /* flag if conditional variable became avail */ + char p_sem_avail; /* flag if semaphore became available */ + pthread_extricate_if *p_extricate; /* See above */ + pthread_readlock_info *p_readlock_list; /* List of readlock info structs */ + pthread_readlock_info *p_readlock_free; /* Free list of structs */ + int p_untracked_readlock_count; /* Readlocks not tracked by list */ + /* New elements must be added at the end. */ +#ifdef __UCLIBC_HAS_XLOCALE__ + __locale_t locale; /* thread-specific locale from uselocale() only! */ +#endif /* __UCLIBC_HAS_XLOCALE__ */ +} __attribute__ ((aligned(32))); /* We need to align the structure so that + doubles are aligned properly. This is 8 + bytes on MIPS and 16 bytes on MIPS64. + 32 bytes might give better cache + utilization. */ + +/* The type of thread handles. */ + +typedef struct pthread_handle_struct * pthread_handle; + +struct pthread_handle_struct { + struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */ + pthread_descr h_descr; /* Thread descriptor or NULL if invalid */ + char * h_bottom; /* Lowest address in the stack thread */ +}; + +/* The type of messages sent to the thread manager thread */ + +struct pthread_request { + pthread_descr req_thread; /* Thread doing the request */ + enum { /* Request kind */ + REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT, + REQ_POST, REQ_DEBUG, REQ_KICK + } req_kind; + union { /* Arguments for request */ + struct { /* For REQ_CREATE: */ + const pthread_attr_t * attr; /* thread attributes */ + void * (*fn)(void *); /* start function */ + void * arg; /* argument to start function */ + sigset_t mask; /* signal mask */ + } create; + struct { /* For REQ_FREE: */ + pthread_t thread_id; /* identifier of thread to free */ + } free; + struct { /* For REQ_PROCESS_EXIT: */ + int code; /* exit status */ + } exit; + void * post; /* For REQ_POST: the semaphore */ + } req_args; +}; + + +/* Signals used for suspend/restart and for cancellation notification. */ + +extern int __pthread_sig_restart; +extern int __pthread_sig_cancel; + +/* Signal used for interfacing with gdb */ + +extern int __pthread_sig_debug; + +/* Global array of thread handles, used for validating a thread id + and retrieving the corresponding thread descriptor. Also used for + mapping the available stack segments. */ + +extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX]; + +/* Descriptor of the initial thread */ + +extern struct _pthread_descr_struct __pthread_initial_thread; + +/* Descriptor of the manager thread */ + +extern struct _pthread_descr_struct __pthread_manager_thread; + +/* Descriptor of the main thread */ + +extern pthread_descr __pthread_main_thread; + +/* Limit between the stack of the initial thread (above) and the + stacks of other threads (below). Aligned on a STACK_SIZE boundary. + Initially 0, meaning that the current thread is (by definition) + the initial thread. */ + +/* For non-MMU systems also remember to stack top of the initial thread. + * This is adapted when other stacks are malloc'ed since we don't know + * the bounds a-priori. -StS */ + +extern char *__pthread_initial_thread_bos; +#ifndef __ARCH_HAS_MMU__ +extern char *__pthread_initial_thread_tos; +#define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) \ + if ((tos)>=__pthread_initial_thread_bos \ + && (bos)<__pthread_initial_thread_tos) \ + __pthread_initial_thread_bos = (tos)+1 +#else +#define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) /* empty */ +#endif /* __ARCH_HAS_MMU__ */ + + +/* Indicate whether at least one thread has a user-defined stack (if 1), + or all threads have stacks supplied by LinuxThreads (if 0). */ + +extern int __pthread_nonstandard_stacks; + +/* File descriptor for sending requests to the thread manager. + Initially -1, meaning that __pthread_initialize_manager must be called. */ + +extern int __pthread_manager_request; + +/* Other end of the pipe for sending requests to the thread manager. */ + +extern int __pthread_manager_reader; + +/* Limits of the thread manager stack. */ + +extern char *__pthread_manager_thread_bos; +extern char *__pthread_manager_thread_tos; + +/* Pending request for a process-wide exit */ + +extern int __pthread_exit_requested, __pthread_exit_code; + +/* Set to 1 by gdb if we're debugging */ + +extern volatile int __pthread_threads_debug; + +/* Globally enabled events. */ +extern volatile td_thr_events_t __pthread_threads_events; + +/* Pointer to descriptor of thread with last event. */ +extern volatile pthread_descr __pthread_last_event; + +/* Return the handle corresponding to a thread id */ + +static inline pthread_handle thread_handle(pthread_t id) +{ + return &__pthread_handles[id % PTHREAD_THREADS_MAX]; +} + +/* Validate a thread handle. Must have acquired h->h_spinlock before. */ + +static inline int invalid_handle(pthread_handle h, pthread_t id) +{ + return h->h_descr == NULL || h->h_descr->p_tid != id; +} + +/* Fill in defaults left unspecified by pt-machine.h. */ + +/* The page size we can get from the system. This should likely not be + changed by the machine file but, you never know. */ +extern size_t __pagesize; +#include +#ifndef PAGE_SIZE +#define PAGE_SIZE (sysconf (_SC_PAGESIZE)) +#endif + +/* The max size of the thread stack segments. If the default + THREAD_SELF implementation is used, this must be a power of two and + a multiple of PAGE_SIZE. */ +#ifndef STACK_SIZE +#ifdef __ARCH_HAS_MMU__ +#define STACK_SIZE (2 * 1024 * 1024) +#else +#define STACK_SIZE (4 * __pagesize) +#endif +#endif + +/* The initial size of the thread stack. Must be a multiple of PAGE_SIZE. */ +#ifndef INITIAL_STACK_SIZE +#define INITIAL_STACK_SIZE (4 * __pagesize) +#endif + +/* Size of the thread manager stack. The "- 32" avoids wasting space + with some malloc() implementations. */ +#ifndef THREAD_MANAGER_STACK_SIZE +#define THREAD_MANAGER_STACK_SIZE (2 * __pagesize - 32) +#endif + +/* The base of the "array" of thread stacks. The array will grow down from + here. Defaults to the calculated bottom of the initial application + stack. */ +#ifndef THREAD_STACK_START_ADDRESS +#define THREAD_STACK_START_ADDRESS __pthread_initial_thread_bos +#endif + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#ifndef CURRENT_STACK_FRAME +#define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) +#endif + +/* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the + architecture doesn't need a memory barrier instruction (e.g. Intel + x86). Still we need the compiler to respect the barrier and emit + all outstanding operations which modify memory. Some architectures + distinguish between full, read and write barriers. */ +#ifndef MEMORY_BARRIER +#define MEMORY_BARRIER() asm ("" : : : "memory") +#endif +#ifndef READ_MEMORY_BARRIER +#define READ_MEMORY_BARRIER() MEMORY_BARRIER() +#endif +#ifndef WRITE_MEMORY_BARRIER +#define WRITE_MEMORY_BARRIER() MEMORY_BARRIER() +#endif + +/* Recover thread descriptor for the current thread */ + +extern pthread_descr __pthread_find_self (void) __attribute__ ((const)); + +static inline pthread_descr thread_self (void) __attribute__ ((const)); +static inline pthread_descr thread_self (void) +{ +#ifdef THREAD_SELF + return THREAD_SELF; +#else + char *sp = CURRENT_STACK_FRAME; +#ifdef __ARCH_HAS_MMU__ + if (sp >= __pthread_initial_thread_bos) + return &__pthread_initial_thread; + else if (sp >= __pthread_manager_thread_bos + && sp < __pthread_manager_thread_tos) + return &__pthread_manager_thread; + else if (__pthread_nonstandard_stacks) + return __pthread_find_self(); + else + return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1; +#else + /* For non-MMU we need to be more careful about the initial thread stack. + * We refine the initial thread stack bounds dynamically as we allocate + * the other stack frame such that it doesn't overlap with them. Then + * we can be sure to pick the right thread according to the current SP */ + + /* Since we allow other stack frames to be above or below, we need to + * treat this case special. When pthread_initialize() wasn't called yet, + * only the initial thread is there. */ + if (__pthread_initial_thread_bos == NULL) { + return &__pthread_initial_thread; + } + else if (sp >= __pthread_initial_thread_bos + && sp < __pthread_initial_thread_tos) { + return &__pthread_initial_thread; + } + else if (sp >= __pthread_manager_thread_bos + && sp < __pthread_manager_thread_tos) { + return &__pthread_manager_thread; + } + else { + return __pthread_find_self(); + } +#endif /* __ARCH_HAS_MMU__ */ +#endif +} + +/* Max number of times we must spin on a spinlock calling sched_yield(). + After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */ + +#ifndef MAX_SPIN_COUNT +#define MAX_SPIN_COUNT 50 +#endif + +/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock + after MAX_SPIN_COUNT iterations of sched_yield(). + With the 2.0 and 2.1 kernels, this MUST BE > 2ms. + (Otherwise the kernel does busy-waiting for realtime threads, + giving other threads no chance to run.) */ + +#ifndef SPIN_SLEEP_DURATION +#define SPIN_SLEEP_DURATION 2000001 +#endif + +/* Debugging */ + +#ifdef DEBUG +#include +#define ASSERT assert +#define MSG __pthread_message +#else +#define ASSERT(x) +#define MSG(msg,arg...) +#endif + +/* Internal global functions */ + +void __pthread_destroy_specifics(void); +void __pthread_perform_cleanup(void); +int __pthread_initialize_manager(void); +void __pthread_message(char * fmt, ...); +int __pthread_manager(void *reqfd); +int __pthread_manager_event(void *reqfd); +void __pthread_manager_sighandler(int sig); +void __pthread_reset_main_thread(void); +void __fresetlockfiles(void); +void __pthread_manager_adjust_prio(int thread_prio); +void __pthread_initialize_minimal (void); + +extern int __pthread_attr_setguardsize __P ((pthread_attr_t *__attr, + size_t __guardsize)); +extern int __pthread_attr_getguardsize __P ((__const pthread_attr_t *__attr, + size_t *__guardsize)); +extern int __pthread_attr_setstackaddr __P ((pthread_attr_t *__attr, + void *__stackaddr)); +extern int __pthread_attr_getstackaddr __P ((__const pthread_attr_t *__attr, + void **__stackaddr)); +extern int __pthread_attr_setstacksize __P ((pthread_attr_t *__attr, + size_t __stacksize)); +extern int __pthread_attr_getstacksize __P ((__const pthread_attr_t *__attr, + size_t *__stacksize)); +extern int __pthread_getconcurrency __P ((void)); +extern int __pthread_setconcurrency __P ((int __level)); +extern int __pthread_mutexattr_gettype __P ((__const pthread_mutexattr_t *__attr, + int *__kind)); +extern void __pthread_kill_other_threads_np __P ((void)); + +extern void __pthread_restart_old(pthread_descr th); +extern void __pthread_suspend_old(pthread_descr self); +extern int __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abs); + +extern void __pthread_restart_new(pthread_descr th); +extern void __pthread_suspend_new(pthread_descr self); +extern int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abs); + +extern void __pthread_wait_for_restart_signal(pthread_descr self); + +/* Global pointers to old or new suspend functions */ + +extern void (*__pthread_restart)(pthread_descr); +extern void (*__pthread_suspend)(pthread_descr); + +/* Prototypes for the function without cancelation support when the + normal version has it. */ +extern int __libc_close (int fd); +extern int __libc_nanosleep (const struct timespec *requested_time, + struct timespec *remaining); +extern ssize_t __libc_read (int fd, void *buf, size_t count); +extern pid_t __libc_waitpid (pid_t pid, int *stat_loc, int options); +extern ssize_t __libc_write (int fd, const void *buf, size_t count); + +/* Prototypes for some of the new semaphore functions. */ +extern int __new_sem_post (sem_t * sem); + +/* The functions called the signal events. */ +extern void __linuxthreads_create_event (void); +extern void __linuxthreads_death_event (void); +extern void __linuxthreads_reap_event (void); + +#endif /* internals.h */ diff --git a/libpthread/linuxthreads.old/join.c b/libpthread/linuxthreads.old/join.c new file mode 100644 index 000000000..5aeec6a20 --- /dev/null +++ b/libpthread/linuxthreads.old/join.c @@ -0,0 +1,221 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Thread termination and joining */ + +#include +#define __USE_GNU +#include +#include +#include +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "debug.h" /* PDEBUG, added by StS */ + +void pthread_exit(void * retval) +{ + pthread_descr self = thread_self(); + pthread_descr joining; + struct pthread_request request; + PDEBUG("self=%p, pid=%d\n", self, self->p_pid); + + /* Reset the cancellation flag to avoid looping if the cleanup handlers + contain cancellation points */ + THREAD_SETMEM(self, p_canceled, 0); + /* Call cleanup functions and destroy the thread-specific data */ + __pthread_perform_cleanup(); + __pthread_destroy_specifics(); + /* Store return value */ + __pthread_lock(THREAD_GETMEM(self, p_lock), self); + THREAD_SETMEM(self, p_retval, retval); + /* See whether we have to signal the death. */ + if (THREAD_GETMEM(self, p_report_events)) + { + /* See whether TD_DEATH is in any of the mask. */ + int idx = __td_eventword (TD_DEATH); + uint32_t mask = __td_eventmask (TD_DEATH); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | THREAD_GETMEM_NC(self, + p_eventbuf.eventmask).event_bits[idx])) + != 0) + { + /* Yep, we have to signal the death. */ + THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH); + THREAD_SETMEM(self, p_eventbuf.eventdata, self); + __pthread_last_event = self; + + /* Now call the function to signal the event. */ + __linuxthreads_death_event(); + } + } + /* Say that we've terminated */ + THREAD_SETMEM(self, p_terminated, 1); + /* See if someone is joining on us */ + joining = THREAD_GETMEM(self, p_joining); + PDEBUG("joining = %p, pid=%d\n", joining, joining->p_pid); + __pthread_unlock(THREAD_GETMEM(self, p_lock)); + /* Restart joining thread if any */ + if (joining != NULL) restart(joining); + /* If this is the initial thread, block until all threads have terminated. + If another thread calls exit, we'll be terminated from our signal + handler. */ + if (self == __pthread_main_thread && __pthread_manager_request >= 0) { + request.req_thread = self; + request.req_kind = REQ_MAIN_THREAD_EXIT; + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *)&request, sizeof(request))); + suspend(self); + /* Main thread flushes stdio streams and runs atexit functions. + * It also calls a handler within LinuxThreads which sends a process exit + * request to the thread manager. */ + exit(0); + } + /* Exit the process (but don't flush stdio streams, and don't run + atexit functions). */ + _exit(0); +} + +/* Function called by pthread_cancel to remove the thread from + waiting on a condition variable queue. */ + +static int join_extricate_func(void *obj, pthread_descr th) +{ + volatile pthread_descr self = thread_self(); + pthread_handle handle = obj; + pthread_descr jo; + int did_remove = 0; + + __pthread_lock(&handle->h_lock, self); + jo = handle->h_descr; + did_remove = jo->p_joining != NULL; + jo->p_joining = NULL; + __pthread_unlock(&handle->h_lock); + + return did_remove; +} + +int pthread_join(pthread_t thread_id, void ** thread_return) +{ + volatile pthread_descr self = thread_self(); + struct pthread_request request; + pthread_handle handle = thread_handle(thread_id); + pthread_descr th; + pthread_extricate_if extr; + int already_canceled = 0; + PDEBUG("\n"); + + /* Set up extrication interface */ + extr.pu_object = handle; + extr.pu_extricate_func = join_extricate_func; + + __pthread_lock(&handle->h_lock, self); + if (invalid_handle(handle, thread_id)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + th = handle->h_descr; + if (th == self) { + __pthread_unlock(&handle->h_lock); + return EDEADLK; + } + /* If detached or already joined, error */ + if (th->p_detached || th->p_joining != NULL) { + __pthread_unlock(&handle->h_lock); + return EINVAL; + } + /* If not terminated yet, suspend ourselves. */ + if (! th->p_terminated) { + /* Register extrication interface */ + __pthread_set_own_extricate_if(self, &extr); + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + th->p_joining = self; + else + already_canceled = 1; + __pthread_unlock(&handle->h_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + pthread_exit(PTHREAD_CANCELED); + } + + PDEBUG("before suspend\n"); + suspend(self); + PDEBUG("after suspend\n"); + /* Deregister extrication interface */ + __pthread_set_own_extricate_if(self, 0); + + /* This is a cancellation point */ + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + pthread_exit(PTHREAD_CANCELED); + } + __pthread_lock(&handle->h_lock, self); + } + /* Get return value */ + if (thread_return != NULL) *thread_return = th->p_retval; + __pthread_unlock(&handle->h_lock); + /* Send notification to thread manager */ + if (__pthread_manager_request >= 0) { + request.req_thread = self; + request.req_kind = REQ_FREE; + request.req_args.free.thread_id = thread_id; + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); + } + return 0; +} + +int pthread_detach(pthread_t thread_id) +{ + int terminated; + struct pthread_request request; + pthread_handle handle = thread_handle(thread_id); + pthread_descr th; + + __pthread_lock(&handle->h_lock, NULL); + if (invalid_handle(handle, thread_id)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + th = handle->h_descr; + /* If already detached, error */ + if (th->p_detached) { + __pthread_unlock(&handle->h_lock); + return EINVAL; + } + /* If already joining, don't do anything. */ + if (th->p_joining != NULL) { + __pthread_unlock(&handle->h_lock); + return 0; + } + /* Mark as detached */ + th->p_detached = 1; + terminated = th->p_terminated; + __pthread_unlock(&handle->h_lock); + /* If already terminated, notify thread manager to reclaim resources */ + if (terminated && __pthread_manager_request >= 0) { + request.req_thread = thread_self(); + request.req_kind = REQ_FREE; + request.req_args.free.thread_id = thread_id; + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); + } + return 0; +} diff --git a/libpthread/linuxthreads.old/linuxthreads.texi b/libpthread/linuxthreads.old/linuxthreads.texi new file mode 100644 index 000000000..795fb7097 --- /dev/null +++ b/libpthread/linuxthreads.old/linuxthreads.texi @@ -0,0 +1,1627 @@ +@node POSIX Threads +@c @node POSIX Threads, , Top, Top +@chapter POSIX Threads +@c %MENU% The standard threads library + +@c This chapter needs more work bigtime. -zw + +This chapter describes the pthreads (POSIX threads) library. This +library provides support functions for multithreaded programs: thread +primitives, synchronization objects, and so forth. It also implements +POSIX 1003.1b semaphores (not to be confused with System V semaphores). + +The threads operations (@samp{pthread_*}) do not use @var{errno}. +Instead they return an error code directly. The semaphore operations do +use @var{errno}. + +@menu +* Basic Thread Operations:: Creating, terminating, and waiting for threads. +* Thread Attributes:: Tuning thread scheduling. +* Cancellation:: Stopping a thread before it's done. +* Cleanup Handlers:: Deallocating resources when a thread is + canceled. +* Mutexes:: One way to synchronize threads. +* Condition Variables:: Another way. +* POSIX Semaphores:: And a third way. +* Thread-Specific Data:: Variables with different values in + different threads. +* Threads and Signal Handling:: Why you should avoid mixing the two, and + how to do it if you must. +* Threads and Fork:: Interactions between threads and the + @code{fork} function. +* Streams and Fork:: Interactions between stdio streams and + @code{fork}. +* Miscellaneous Thread Functions:: A grab bag of utility routines. +@end menu + +@node Basic Thread Operations +@section Basic Thread Operations + +These functions are the thread equivalents of @code{fork}, @code{exit}, +and @code{wait}. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_create (pthread_t * @var{thread}, pthread_attr_t * @var{attr}, void * (*@var{start_routine})(void *), void * @var{arg}) +@code{pthread_create} creates a new thread of control that executes +concurrently with the calling thread. The new thread calls the +function @var{start_routine}, passing it @var{arg} as first argument. The +new thread terminates either explicitly, by calling @code{pthread_exit}, +or implicitly, by returning from the @var{start_routine} function. The +latter case is equivalent to calling @code{pthread_exit} with the result +returned by @var{start_routine} as exit code. + +The @var{attr} argument specifies thread attributes to be applied to the +new thread. @xref{Thread Attributes}, for details. The @var{attr} +argument can also be @code{NULL}, in which case default attributes are +used: the created thread is joinable (not detached) and has an ordinary +(not realtime) scheduling policy. + +On success, the identifier of the newly created thread is stored in the +location pointed by the @var{thread} argument, and a 0 is returned. On +error, a non-zero error code is returned. + +This function may return the following errors: +@table @code +@item EAGAIN +Not enough system resources to create a process for the new thread, +or more than @code{PTHREAD_THREADS_MAX} threads are already active. +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun void pthread_exit (void *@var{retval}) +@code{pthread_exit} terminates the execution of the calling thread. All +cleanup handlers (@pxref{Cleanup Handlers}) that have been set for the +calling thread with @code{pthread_cleanup_push} are executed in reverse +order (the most recently pushed handler is executed first). Finalization +functions for thread-specific data are then called for all keys that +have non-@code{NULL} values associated with them in the calling thread +(@pxref{Thread-Specific Data}). Finally, execution of the calling +thread is stopped. + +The @var{retval} argument is the return value of the thread. It can be +retrieved from another thread using @code{pthread_join}. + +The @code{pthread_exit} function never returns. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cancel (pthread_t @var{thread}) + +@code{pthread_cancel} sends a cancellation request to the thread denoted +by the @var{thread} argument. If there is no such thread, +@code{pthread_cancel} fails and returns @code{ESRCH}. Otherwise it +returns 0. @xref{Cancellation}, for details. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_join (pthread_t @var{th}, void **thread_@var{return}) +@code{pthread_join} suspends the execution of the calling thread until +the thread identified by @var{th} terminates, either by calling +@code{pthread_exit} or by being canceled. + +If @var{thread_return} is not @code{NULL}, the return value of @var{th} +is stored in the location pointed to by @var{thread_return}. The return +value of @var{th} is either the argument it gave to @code{pthread_exit}, +or @code{PTHREAD_CANCELED} if @var{th} was canceled. + +The joined thread @code{th} must be in the joinable state: it must not +have been detached using @code{pthread_detach} or the +@code{PTHREAD_CREATE_DETACHED} attribute to @code{pthread_create}. + +When a joinable thread terminates, its memory resources (thread +descriptor and stack) are not deallocated until another thread performs +@code{pthread_join} on it. Therefore, @code{pthread_join} must be called +once for each joinable thread created to avoid memory leaks. + +At most one thread can wait for the termination of a given +thread. Calling @code{pthread_join} on a thread @var{th} on which +another thread is already waiting for termination returns an error. + +@code{pthread_join} is a cancellation point. If a thread is canceled +while suspended in @code{pthread_join}, the thread execution resumes +immediately and the cancellation is executed without waiting for the +@var{th} thread to terminate. If cancellation occurs during +@code{pthread_join}, the @var{th} thread remains not joined. + +On success, the return value of @var{th} is stored in the location +pointed to by @var{thread_return}, and 0 is returned. On error, one of +the following values is returned: +@table @code +@item ESRCH +No thread could be found corresponding to that specified by @var{th}. +@item EINVAL +The @var{th} thread has been detached, or another thread is already +waiting on termination of @var{th}. +@item EDEADLK +The @var{th} argument refers to the calling thread. +@end table +@end deftypefun + +@node Thread Attributes +@section Thread Attributes + +@comment pthread.h +@comment POSIX + +Threads have a number of attributes that may be set at creation time. +This is done by filling a thread attribute object @var{attr} of type +@code{pthread_attr_t}, then passing it as second argument to +@code{pthread_create}. Passing @code{NULL} is equivalent to passing a +thread attribute object with all attributes set to their default values. + +Attribute objects are consulted only when creating a new thread. The +same attribute object can be used for creating several threads. +Modifying an attribute object after a call to @code{pthread_create} does +not change the attributes of the thread previously created. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_attr_init (pthread_attr_t *@var{attr}) +@code{pthread_attr_init} initializes the thread attribute object +@var{attr} and fills it with default values for the attributes. (The +default values are listed below for each attribute.) + +Each attribute @var{attrname} (see below for a list of all attributes) +can be individually set using the function +@code{pthread_attr_set@var{attrname}} and retrieved using the function +@code{pthread_attr_get@var{attrname}}. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_attr_destroy (pthread_attr_t *@var{attr}) +@code{pthread_attr_destroy} destroys the attribute object pointed to by +@var{attr} releasing any resources associated with it. @var{attr} is +left in an undefined state, and you must not use it again in a call to +any pthreads function until it has been reinitialized. +@end deftypefun + +@findex pthread_attr_setdetachstate +@findex pthread_attr_setguardsize +@findex pthread_attr_setinheritsched +@findex pthread_attr_setschedparam +@findex pthread_attr_setschedpolicy +@findex pthread_attr_setscope +@findex pthread_attr_setstack +@findex pthread_attr_setstackaddr +@findex pthread_attr_setstacksize +@comment pthread.h +@comment POSIX +@deftypefun int pthread_attr_setattr (pthread_attr_t *@var{obj}, int @var{value}) +Set attribute @var{attr} to @var{value} in the attribute object pointed +to by @var{obj}. See below for a list of possible attributes and the +values they can take. + +On success, these functions return 0. If @var{value} is not meaningful +for the @var{attr} being modified, they will return the error code +@code{EINVAL}. Some of the functions have other failure modes; see +below. +@end deftypefun + +@findex pthread_attr_getdetachstate +@findex pthread_attr_getguardsize +@findex pthread_attr_getinheritsched +@findex pthread_attr_getschedparam +@findex pthread_attr_getschedpolicy +@findex pthread_attr_getscope +@findex pthread_attr_getstack +@findex pthread_attr_getstackaddr +@findex pthread_attr_getstacksize +@comment pthread.h +@comment POSIX +@deftypefun int pthread_attr_getattr (const pthread_attr_t *@var{obj}, int *@var{value}) +Store the current setting of @var{attr} in @var{obj} into the variable +pointed to by @var{value}. + +These functions always return 0. +@end deftypefun + +The following thread attributes are supported: +@table @samp +@item detachstate +Choose whether the thread is created in the joinable state (value +@code{PTHREAD_CREATE_JOINABLE}) or in the detached state +(@code{PTHREAD_CREATE_DETACHED}). The default is +@code{PTHREAD_CREATE_JOINABLE}. + +In the joinable state, another thread can synchronize on the thread +termination and recover its termination code using @code{pthread_join}, +but some of the thread resources are kept allocated after the thread +terminates, and reclaimed only when another thread performs +@code{pthread_join} on that thread. + +In the detached state, the thread resources are immediately freed when +it terminates, but @code{pthread_join} cannot be used to synchronize on +the thread termination. + +A thread created in the joinable state can later be put in the detached +thread using @code{pthread_detach}. + +@item schedpolicy +Select the scheduling policy for the thread: one of @code{SCHED_OTHER} +(regular, non-realtime scheduling), @code{SCHED_RR} (realtime, +round-robin) or @code{SCHED_FIFO} (realtime, first-in first-out). +The default is @code{SCHED_OTHER}. +@c Not doc'd in our manual: FIXME. +@c See @code{sched_setpolicy} for more information on scheduling policies. + +The realtime scheduling policies @code{SCHED_RR} and @code{SCHED_FIFO} +are available only to processes with superuser privileges. +@code{pthread_attr_setschedparam} will fail and return @code{ENOTSUP} if +you try to set a realtime policy when you are unprivileged. + +The scheduling policy of a thread can be changed after creation with +@code{pthread_setschedparam}. + +@item schedparam +Change the scheduling parameter (the scheduling priority) +for the thread. The default is 0. + +This attribute is not significant if the scheduling policy is +@code{SCHED_OTHER}; it only matters for the realtime policies +@code{SCHED_RR} and @code{SCHED_FIFO}. + +The scheduling priority of a thread can be changed after creation with +@code{pthread_setschedparam}. + +@item inheritsched +Choose whether the scheduling policy and scheduling parameter for the +newly created thread are determined by the values of the +@var{schedpolicy} and @var{schedparam} attributes (value +@code{PTHREAD_EXPLICIT_SCHED}) or are inherited from the parent thread +(value @code{PTHREAD_INHERIT_SCHED}). The default is +@code{PTHREAD_EXPLICIT_SCHED}. + +@item scope +Choose the scheduling contention scope for the created thread. The +default is @code{PTHREAD_SCOPE_SYSTEM}, meaning that the threads contend +for CPU time with all processes running on the machine. In particular, +thread priorities are interpreted relative to the priorities of all +other processes on the machine. The other possibility, +@code{PTHREAD_SCOPE_PROCESS}, means that scheduling contention occurs +only between the threads of the running process: thread priorities are +interpreted relative to the priorities of the other threads of the +process, regardless of the priorities of other processes. + +@code{PTHREAD_SCOPE_PROCESS} is not supported in LinuxThreads. If you +try to set the scope to this value, @code{pthread_attr_setscope} will +fail and return @code{ENOTSUP}. + +@item stackaddr +Provide an address for an application managed stack. The size of the +stack must be at least @code{PTHREAD_STACK_MIN}. + +@item stacksize +Change the size of the stack created for the thread. The value defines +the minimum stack size, in bytes. + +If the value exceeds the system's maximum stack size, or is smaller +than @code{PTHREAD_STACK_MIN}, @code{pthread_attr_setstacksize} will +fail and return @code{EINVAL}. + +@item stack +Provide both the address and size of an application managed stack to +use for the new thread. The base of the memory area is @var{stackaddr} +with the size of the memory area, @var{stacksize}, measured in bytes. + +If the value of @var{stacksize} is less than @code{PTHREAD_STACK_MIN}, +or greater than the system's maximum stack size, or if the value of +@var{stackaddr} lacks the proper alignment, @code{pthread_attr_setstack} +will fail and return @code{EINVAL}. + +@item guardsize +Change the minimum size in bytes of the guard area for the thread's +stack. The default size is a single page. If this value is set, it +will be rounded up to the nearest page size. If the value is set to 0, +a guard area will not be created for this thread. The space allocated +for the guard area is used to catch stack overflow. Therefore, when +allocating large structures on the stack, a larger guard area may be +required to catch a stack overflow. + +If the caller is managing their own stacks (if the @code{stackaddr} +attribute has been set), then the @code{guardsize} attribute is ignored. + +If the value exceeds the @code{stacksize}, @code{pthread_atrr_setguardsize} +will fail and return @code{EINVAL}. +@end table + +@node Cancellation +@section Cancellation + +Cancellation is the mechanism by which a thread can terminate the +execution of another thread. More precisely, a thread can send a +cancellation request to another thread. Depending on its settings, the +target thread can then either ignore the request, honor it immediately, +or defer it till it reaches a cancellation point. When threads are +first created by @code{pthread_create}, they always defer cancellation +requests. + +When a thread eventually honors a cancellation request, it behaves as if +@code{pthread_exit(PTHREAD_CANCELED)} was called. All cleanup handlers +are executed in reverse order, finalization functions for +thread-specific data are called, and finally the thread stops executing. +If the canceled thread was joinable, the return value +@code{PTHREAD_CANCELED} is provided to whichever thread calls +@var{pthread_join} on it. See @code{pthread_exit} for more information. + +Cancellation points are the points where the thread checks for pending +cancellation requests and performs them. The POSIX threads functions +@code{pthread_join}, @code{pthread_cond_wait}, +@code{pthread_cond_timedwait}, @code{pthread_testcancel}, +@code{sem_wait}, and @code{sigwait} are cancellation points. In +addition, these system calls are cancellation points: + +@multitable @columnfractions .33 .33 .33 +@item @t{accept} @tab @t{open} @tab @t{sendmsg} +@item @t{close} @tab @t{pause} @tab @t{sendto} +@item @t{connect} @tab @t{read} @tab @t{system} +@item @t{fcntl} @tab @t{recv} @tab @t{tcdrain} +@item @t{fsync} @tab @t{recvfrom} @tab @t{wait} +@item @t{lseek} @tab @t{recvmsg} @tab @t{waitpid} +@item @t{msync} @tab @t{send} @tab @t{write} +@item @t{nanosleep} +@end multitable + +@noindent +All library functions that call these functions (such as +@code{printf}) are also cancellation points. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setcancelstate (int @var{state}, int *@var{oldstate}) +@code{pthread_setcancelstate} changes the cancellation state for the +calling thread -- that is, whether cancellation requests are ignored or +not. The @var{state} argument is the new cancellation state: either +@code{PTHREAD_CANCEL_ENABLE} to enable cancellation, or +@code{PTHREAD_CANCEL_DISABLE} to disable cancellation (cancellation +requests are ignored). + +If @var{oldstate} is not @code{NULL}, the previous cancellation state is +stored in the location pointed to by @var{oldstate}, and can thus be +restored later by another call to @code{pthread_setcancelstate}. + +If the @var{state} argument is not @code{PTHREAD_CANCEL_ENABLE} or +@code{PTHREAD_CANCEL_DISABLE}, @code{pthread_setcancelstate} fails and +returns @code{EINVAL}. Otherwise it returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setcanceltype (int @var{type}, int *@var{oldtype}) +@code{pthread_setcanceltype} changes the type of responses to +cancellation requests for the calling thread: asynchronous (immediate) +or deferred. The @var{type} argument is the new cancellation type: +either @code{PTHREAD_CANCEL_ASYNCHRONOUS} to cancel the calling thread +as soon as the cancellation request is received, or +@code{PTHREAD_CANCEL_DEFERRED} to keep the cancellation request pending +until the next cancellation point. If @var{oldtype} is not @code{NULL}, +the previous cancellation state is stored in the location pointed to by +@var{oldtype}, and can thus be restored later by another call to +@code{pthread_setcanceltype}. + +If the @var{type} argument is not @code{PTHREAD_CANCEL_DEFERRED} or +@code{PTHREAD_CANCEL_ASYNCHRONOUS}, @code{pthread_setcanceltype} fails +and returns @code{EINVAL}. Otherwise it returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun void pthread_testcancel (@var{void}) +@code{pthread_testcancel} does nothing except testing for pending +cancellation and executing it. Its purpose is to introduce explicit +checks for cancellation in long sequences of code that do not call +cancellation point functions otherwise. +@end deftypefun + +@node Cleanup Handlers +@section Cleanup Handlers + +Cleanup handlers are functions that get called when a thread terminates, +either by calling @code{pthread_exit} or because of +cancellation. Cleanup handlers are installed and removed following a +stack-like discipline. + +The purpose of cleanup handlers is to free the resources that a thread +may hold at the time it terminates. In particular, if a thread exits or +is canceled while it owns a locked mutex, the mutex will remain locked +forever and prevent other threads from executing normally. The best way +to avoid this is, just before locking the mutex, to install a cleanup +handler whose effect is to unlock the mutex. Cleanup handlers can be +used similarly to free blocks allocated with @code{malloc} or close file +descriptors on thread termination. + +Here is how to lock a mutex @var{mut} in such a way that it will be +unlocked if the thread is canceled while @var{mut} is locked: + +@smallexample +pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_mutex_unlock(&mut); +pthread_cleanup_pop(0); +@end smallexample + +Equivalently, the last two lines can be replaced by + +@smallexample +pthread_cleanup_pop(1); +@end smallexample + +Notice that the code above is safe only in deferred cancellation mode +(see @code{pthread_setcanceltype}). In asynchronous cancellation mode, a +cancellation can occur between @code{pthread_cleanup_push} and +@code{pthread_mutex_lock}, or between @code{pthread_mutex_unlock} and +@code{pthread_cleanup_pop}, resulting in both cases in the thread trying +to unlock a mutex not locked by the current thread. This is the main +reason why asynchronous cancellation is difficult to use. + +If the code above must also work in asynchronous cancellation mode, +then it must switch to deferred mode for locking and unlocking the +mutex: + +@smallexample +pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); +pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_cleanup_pop(1); +pthread_setcanceltype(oldtype, NULL); +@end smallexample + +The code above can be rewritten in a more compact and efficient way, +using the non-portable functions @code{pthread_cleanup_push_defer_np} +and @code{pthread_cleanup_pop_restore_np}: + +@smallexample +pthread_cleanup_push_defer_np(pthread_mutex_unlock, (void *) &mut); +pthread_mutex_lock(&mut); +/* do some work */ +pthread_cleanup_pop_restore_np(1); +@end smallexample + +@comment pthread.h +@comment POSIX +@deftypefun void pthread_cleanup_push (void (*@var{routine}) (void *), void *@var{arg}) + +@code{pthread_cleanup_push} installs the @var{routine} function with +argument @var{arg} as a cleanup handler. From this point on to the +matching @code{pthread_cleanup_pop}, the function @var{routine} will be +called with arguments @var{arg} when the thread terminates, either +through @code{pthread_exit} or by cancellation. If several cleanup +handlers are active at that point, they are called in LIFO order: the +most recently installed handler is called first. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun void pthread_cleanup_pop (int @var{execute}) +@code{pthread_cleanup_pop} removes the most recently installed cleanup +handler. If the @var{execute} argument is not 0, it also executes the +handler, by calling the @var{routine} function with arguments +@var{arg}. If the @var{execute} argument is 0, the handler is only +removed but not executed. +@end deftypefun + +Matching pairs of @code{pthread_cleanup_push} and +@code{pthread_cleanup_pop} must occur in the same function, at the same +level of block nesting. Actually, @code{pthread_cleanup_push} and +@code{pthread_cleanup_pop} are macros, and the expansion of +@code{pthread_cleanup_push} introduces an open brace @code{@{} with the +matching closing brace @code{@}} being introduced by the expansion of the +matching @code{pthread_cleanup_pop}. + +@comment pthread.h +@comment GNU +@deftypefun void pthread_cleanup_push_defer_np (void (*@var{routine}) (void *), void *@var{arg}) +@code{pthread_cleanup_push_defer_np} is a non-portable extension that +combines @code{pthread_cleanup_push} and @code{pthread_setcanceltype}. +It pushes a cleanup handler just as @code{pthread_cleanup_push} does, +but also saves the current cancellation type and sets it to deferred +cancellation. This ensures that the cleanup mechanism is effective even +if the thread was initially in asynchronous cancellation mode. +@end deftypefun + +@comment pthread.h +@comment GNU +@deftypefun void pthread_cleanup_pop_restore_np (int @var{execute}) +@code{pthread_cleanup_pop_restore_np} pops a cleanup handler introduced +by @code{pthread_cleanup_push_defer_np}, and restores the cancellation +type to its value at the time @code{pthread_cleanup_push_defer_np} was +called. +@end deftypefun + +@code{pthread_cleanup_push_defer_np} and +@code{pthread_cleanup_pop_restore_np} must occur in matching pairs, at +the same level of block nesting. + +The sequence + +@smallexample +pthread_cleanup_push_defer_np(routine, arg); +... +pthread_cleanup_pop_restore_np(execute); +@end smallexample + +@noindent +is functionally equivalent to (but more compact and efficient than) + +@smallexample +@{ + int oldtype; + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); + pthread_cleanup_push(routine, arg); + ... + pthread_cleanup_pop(execute); + pthread_setcanceltype(oldtype, NULL); +@} +@end smallexample + + +@node Mutexes +@section Mutexes + +A mutex is a MUTual EXclusion device, and is useful for protecting +shared data structures from concurrent modifications, and implementing +critical sections and monitors. + +A mutex has two possible states: unlocked (not owned by any thread), +and locked (owned by one thread). A mutex can never be owned by two +different threads simultaneously. A thread attempting to lock a mutex +that is already locked by another thread is suspended until the owning +thread unlocks the mutex first. + +None of the mutex functions is a cancellation point, not even +@code{pthread_mutex_lock}, in spite of the fact that it can suspend a +thread for arbitrary durations. This way, the status of mutexes at +cancellation points is predictable, allowing cancellation handlers to +unlock precisely those mutexes that need to be unlocked before the +thread stops executing. Consequently, threads using deferred +cancellation should never hold a mutex for extended periods of time. + +It is not safe to call mutex functions from a signal handler. In +particular, calling @code{pthread_mutex_lock} or +@code{pthread_mutex_unlock} from a signal handler may deadlock the +calling thread. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_init (pthread_mutex_t *@var{mutex}, const pthread_mutexattr_t *@var{mutexattr}) + +@code{pthread_mutex_init} initializes the mutex object pointed to by +@var{mutex} according to the mutex attributes specified in @var{mutexattr}. +If @var{mutexattr} is @code{NULL}, default attributes are used instead. + +The LinuxThreads implementation supports only one mutex attribute, +the @var{mutex type}, which is either ``fast'', ``recursive'', or +``error checking''. The type of a mutex determines whether +it can be locked again by a thread that already owns it. +The default type is ``fast''. + +Variables of type @code{pthread_mutex_t} can also be initialized +statically, using the constants @code{PTHREAD_MUTEX_INITIALIZER} (for +timed mutexes), @code{PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} (for +recursive mutexes), @code{PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP} +(for fast mutexes(, and @code{PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP} +(for error checking mutexes). + +@code{pthread_mutex_init} always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_lock (pthread_mutex_t *mutex)) +@code{pthread_mutex_lock} locks the given mutex. If the mutex is +currently unlocked, it becomes locked and owned by the calling thread, +and @code{pthread_mutex_lock} returns immediately. If the mutex is +already locked by another thread, @code{pthread_mutex_lock} suspends the +calling thread until the mutex is unlocked. + +If the mutex is already locked by the calling thread, the behavior of +@code{pthread_mutex_lock} depends on the type of the mutex. If the mutex +is of the ``fast'' type, the calling thread is suspended. It will +remain suspended forever, because no other thread can unlock the mutex. +If the mutex is of the ``error checking'' type, @code{pthread_mutex_lock} +returns immediately with the error code @code{EDEADLK}. If the mutex is +of the ``recursive'' type, @code{pthread_mutex_lock} succeeds and +returns immediately, recording the number of times the calling thread +has locked the mutex. An equal number of @code{pthread_mutex_unlock} +operations must be performed before the mutex returns to the unlocked +state. +@c This doesn't discuss PTHREAD_MUTEX_TIMED_NP mutex attributes. FIXME +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_trylock (pthread_mutex_t *@var{mutex}) +@code{pthread_mutex_trylock} behaves identically to +@code{pthread_mutex_lock}, except that it does not block the calling +thread if the mutex is already locked by another thread (or by the +calling thread in the case of a ``fast'' mutex). Instead, +@code{pthread_mutex_trylock} returns immediately with the error code +@code{EBUSY}. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_timedlock (pthread_mutex_t *@var{mutex}, const struct timespec *@var{abstime}) +The @code{pthread_mutex_timedlock} is similar to the +@code{pthread_mutex_lock} function but instead of blocking for in +indefinite time if the mutex is locked by another thread, it returns +when the time specified in @var{abstime} is reached. + +This function can only be used on standard (``timed'') and ``error +checking'' mutexes. It behaves just like @code{pthread_mutex_lock} for +all other types. + +If the mutex is successfully locked, the function returns zero. If the +time specified in @var{abstime} is reached without the mutex being locked, +@code{ETIMEDOUT} is returned. + +This function was introduced in the POSIX.1d revision of the POSIX standard. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_unlock (pthread_mutex_t *@var{mutex}) +@code{pthread_mutex_unlock} unlocks the given mutex. The mutex is +assumed to be locked and owned by the calling thread on entrance to +@code{pthread_mutex_unlock}. If the mutex is of the ``fast'' type, +@code{pthread_mutex_unlock} always returns it to the unlocked state. If +it is of the ``recursive'' type, it decrements the locking count of the +mutex (number of @code{pthread_mutex_lock} operations performed on it by +the calling thread), and only when this count reaches zero is the mutex +actually unlocked. + +On ``error checking'' mutexes, @code{pthread_mutex_unlock} actually +checks at run-time that the mutex is locked on entrance, and that it was +locked by the same thread that is now calling +@code{pthread_mutex_unlock}. If these conditions are not met, +@code{pthread_mutex_unlock} returns @code{EPERM}, and the mutex remains +unchanged. ``Fast'' and ``recursive'' mutexes perform no such checks, +thus allowing a locked mutex to be unlocked by a thread other than its +owner. This is non-portable behavior and must not be relied upon. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutex_destroy (pthread_mutex_t *@var{mutex}) +@code{pthread_mutex_destroy} destroys a mutex object, freeing the +resources it might hold. The mutex must be unlocked on entrance. In the +LinuxThreads implementation, no resources are associated with mutex +objects, thus @code{pthread_mutex_destroy} actually does nothing except +checking that the mutex is unlocked. + +If the mutex is locked by some thread, @code{pthread_mutex_destroy} +returns @code{EBUSY}. Otherwise it returns 0. +@end deftypefun + +If any of the above functions (except @code{pthread_mutex_init}) +is applied to an uninitialized mutex, they will simply return +@code{EINVAL} and do nothing. + +A shared global variable @var{x} can be protected by a mutex as follows: + +@smallexample +int x; +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +@end smallexample + +All accesses and modifications to @var{x} should be bracketed by calls to +@code{pthread_mutex_lock} and @code{pthread_mutex_unlock} as follows: + +@smallexample +pthread_mutex_lock(&mut); +/* operate on x */ +pthread_mutex_unlock(&mut); +@end smallexample + +Mutex attributes can be specified at mutex creation time, by passing a +mutex attribute object as second argument to @code{pthread_mutex_init}. +Passing @code{NULL} is equivalent to passing a mutex attribute object +with all attributes set to their default values. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutexattr_init (pthread_mutexattr_t *@var{attr}) +@code{pthread_mutexattr_init} initializes the mutex attribute object +@var{attr} and fills it with default values for the attributes. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutexattr_destroy (pthread_mutexattr_t *@var{attr}) +@code{pthread_mutexattr_destroy} destroys a mutex attribute object, +which must not be reused until it is +reinitialized. @code{pthread_mutexattr_destroy} does nothing in the +LinuxThreads implementation. + +This function always returns 0. +@end deftypefun + +LinuxThreads supports only one mutex attribute: the mutex type, which is +either @code{PTHREAD_MUTEX_ADAPTIVE_NP} for ``fast'' mutexes, +@code{PTHREAD_MUTEX_RECURSIVE_NP} for ``recursive'' mutexes, +@code{PTHREAD_MUTEX_TIMED_NP} for ``timed'' mutexes, or +@code{PTHREAD_MUTEX_ERRORCHECK_NP} for ``error checking'' mutexes. As +the @code{NP} suffix indicates, this is a non-portable extension to the +POSIX standard and should not be employed in portable programs. + +The mutex type determines what happens if a thread attempts to lock a +mutex it already owns with @code{pthread_mutex_lock}. If the mutex is of +the ``fast'' type, @code{pthread_mutex_lock} simply suspends the calling +thread forever. If the mutex is of the ``error checking'' type, +@code{pthread_mutex_lock} returns immediately with the error code +@code{EDEADLK}. If the mutex is of the ``recursive'' type, the call to +@code{pthread_mutex_lock} returns immediately with a success return +code. The number of times the thread owning the mutex has locked it is +recorded in the mutex. The owning thread must call +@code{pthread_mutex_unlock} the same number of times before the mutex +returns to the unlocked state. + +The default mutex type is ``timed'', that is, @code{PTHREAD_MUTEX_TIMED_NP}. +@c This doesn't describe how a ``timed'' mutex behaves. FIXME + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutexattr_settype (pthread_mutexattr_t *@var{attr}, int @var{type}) +@code{pthread_mutexattr_settype} sets the mutex type attribute in +@var{attr} to the value specified by @var{type}. + +If @var{type} is not @code{PTHREAD_MUTEX_ADAPTIVE_NP}, +@code{PTHREAD_MUTEX_RECURSIVE_NP}, @code{PTHREAD_MUTEX_TIMED_NP}, or +@code{PTHREAD_MUTEX_ERRORCHECK_NP}, this function will return +@code{EINVAL} and leave @var{attr} unchanged. + +The standard Unix98 identifiers @code{PTHREAD_MUTEX_DEFAULT}, +@code{PTHREAD_MUTEX_NORMAL}, @code{PTHREAD_MUTEX_RECURSIVE}, +and @code{PTHREAD_MUTEX_ERRORCHECK} are also permitted. + +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_mutexattr_gettype (const pthread_mutexattr_t *@var{attr}, int *@var{type}) +@code{pthread_mutexattr_gettype} retrieves the current value of the +mutex type attribute in @var{attr} and stores it in the location pointed +to by @var{type}. + +This function always returns 0. +@end deftypefun + +@node Condition Variables +@section Condition Variables + +A condition (short for ``condition variable'') is a synchronization +device that allows threads to suspend execution until some predicate on +shared data is satisfied. The basic operations on conditions are: signal +the condition (when the predicate becomes true), and wait for the +condition, suspending the thread execution until another thread signals +the condition. + +A condition variable must always be associated with a mutex, to avoid +the race condition where a thread prepares to wait on a condition +variable and another thread signals the condition just before the first +thread actually waits on it. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_init (pthread_cond_t *@var{cond}, pthread_condattr_t *cond_@var{attr}) + +@code{pthread_cond_init} initializes the condition variable @var{cond}, +using the condition attributes specified in @var{cond_attr}, or default +attributes if @var{cond_attr} is @code{NULL}. The LinuxThreads +implementation supports no attributes for conditions, hence the +@var{cond_attr} parameter is actually ignored. + +Variables of type @code{pthread_cond_t} can also be initialized +statically, using the constant @code{PTHREAD_COND_INITIALIZER}. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_signal (pthread_cond_t *@var{cond}) +@code{pthread_cond_signal} restarts one of the threads that are waiting +on the condition variable @var{cond}. If no threads are waiting on +@var{cond}, nothing happens. If several threads are waiting on +@var{cond}, exactly one is restarted, but it is not specified which. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_broadcast (pthread_cond_t *@var{cond}) +@code{pthread_cond_broadcast} restarts all the threads that are waiting +on the condition variable @var{cond}. Nothing happens if no threads are +waiting on @var{cond}. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_wait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}) +@code{pthread_cond_wait} atomically unlocks the @var{mutex} (as per +@code{pthread_unlock_mutex}) and waits for the condition variable +@var{cond} to be signaled. The thread execution is suspended and does +not consume any CPU time until the condition variable is signaled. The +@var{mutex} must be locked by the calling thread on entrance to +@code{pthread_cond_wait}. Before returning to the calling thread, +@code{pthread_cond_wait} re-acquires @var{mutex} (as per +@code{pthread_lock_mutex}). + +Unlocking the mutex and suspending on the condition variable is done +atomically. Thus, if all threads always acquire the mutex before +signaling the condition, this guarantees that the condition cannot be +signaled (and thus ignored) between the time a thread locks the mutex +and the time it waits on the condition variable. + +This function always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_timedwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}, const struct timespec *@var{abstime}) +@code{pthread_cond_timedwait} atomically unlocks @var{mutex} and waits +on @var{cond}, as @code{pthread_cond_wait} does, but it also bounds the +duration of the wait. If @var{cond} has not been signaled before time +@var{abstime}, the mutex @var{mutex} is re-acquired and +@code{pthread_cond_timedwait} returns the error code @code{ETIMEDOUT}. +The wait can also be interrupted by a signal; in that case +@code{pthread_cond_timedwait} returns @code{EINTR}. + +The @var{abstime} parameter specifies an absolute time, with the same +origin as @code{time} and @code{gettimeofday}: an @var{abstime} of 0 +corresponds to 00:00:00 GMT, January 1, 1970. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_cond_destroy (pthread_cond_t *@var{cond}) +@code{pthread_cond_destroy} destroys the condition variable @var{cond}, +freeing the resources it might hold. If any threads are waiting on the +condition variable, @code{pthread_cond_destroy} leaves @var{cond} +untouched and returns @code{EBUSY}. Otherwise it returns 0, and +@var{cond} must not be used again until it is reinitialized. + +In the LinuxThreads implementation, no resources are associated with +condition variables, so @code{pthread_cond_destroy} actually does +nothing. +@end deftypefun + +@code{pthread_cond_wait} and @code{pthread_cond_timedwait} are +cancellation points. If a thread is canceled while suspended in one of +these functions, the thread immediately resumes execution, relocks the +mutex specified by @var{mutex}, and finally executes the cancellation. +Consequently, cleanup handlers are assured that @var{mutex} is locked +when they are called. + +It is not safe to call the condition variable functions from a signal +handler. In particular, calling @code{pthread_cond_signal} or +@code{pthread_cond_broadcast} from a signal handler may deadlock the +calling thread. + +Consider two shared variables @var{x} and @var{y}, protected by the +mutex @var{mut}, and a condition variable @var{cond} that is to be +signaled whenever @var{x} becomes greater than @var{y}. + +@smallexample +int x,y; +pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +@end smallexample + +Waiting until @var{x} is greater than @var{y} is performed as follows: + +@smallexample +pthread_mutex_lock(&mut); +while (x <= y) @{ + pthread_cond_wait(&cond, &mut); +@} +/* operate on x and y */ +pthread_mutex_unlock(&mut); +@end smallexample + +Modifications on @var{x} and @var{y} that may cause @var{x} to become greater than +@var{y} should signal the condition if needed: + +@smallexample +pthread_mutex_lock(&mut); +/* modify x and y */ +if (x > y) pthread_cond_broadcast(&cond); +pthread_mutex_unlock(&mut); +@end smallexample + +If it can be proved that at most one waiting thread needs to be waken +up (for instance, if there are only two threads communicating through +@var{x} and @var{y}), @code{pthread_cond_signal} can be used as a slightly more +efficient alternative to @code{pthread_cond_broadcast}. In doubt, use +@code{pthread_cond_broadcast}. + +To wait for @var{x} to becomes greater than @var{y} with a timeout of 5 +seconds, do: + +@smallexample +struct timeval now; +struct timespec timeout; +int retcode; + +pthread_mutex_lock(&mut); +gettimeofday(&now); +timeout.tv_sec = now.tv_sec + 5; +timeout.tv_nsec = now.tv_usec * 1000; +retcode = 0; +while (x <= y && retcode != ETIMEDOUT) @{ + retcode = pthread_cond_timedwait(&cond, &mut, &timeout); +@} +if (retcode == ETIMEDOUT) @{ + /* timeout occurred */ +@} else @{ + /* operate on x and y */ +@} +pthread_mutex_unlock(&mut); +@end smallexample + +Condition attributes can be specified at condition creation time, by +passing a condition attribute object as second argument to +@code{pthread_cond_init}. Passing @code{NULL} is equivalent to passing +a condition attribute object with all attributes set to their default +values. + +The LinuxThreads implementation supports no attributes for +conditions. The functions on condition attributes are included only for +compliance with the POSIX standard. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_condattr_init (pthread_condattr_t *@var{attr}) +@deftypefunx int pthread_condattr_destroy (pthread_condattr_t *@var{attr}) +@code{pthread_condattr_init} initializes the condition attribute object +@var{attr} and fills it with default values for the attributes. +@code{pthread_condattr_destroy} destroys the condition attribute object +@var{attr}. + +Both functions do nothing in the LinuxThreads implementation. + +@code{pthread_condattr_init} and @code{pthread_condattr_destroy} always +return 0. +@end deftypefun + +@node POSIX Semaphores +@section POSIX Semaphores + +@vindex SEM_VALUE_MAX +Semaphores are counters for resources shared between threads. The +basic operations on semaphores are: increment the counter atomically, +and wait until the counter is non-null and decrement it atomically. + +Semaphores have a maximum value past which they cannot be incremented. +The macro @code{SEM_VALUE_MAX} is defined to be this maximum value. In +the GNU C library, @code{SEM_VALUE_MAX} is equal to @code{INT_MAX} +(@pxref{Range of Type}), but it may be much smaller on other systems. + +The pthreads library implements POSIX 1003.1b semaphores. These should +not be confused with System V semaphores (@code{ipc}, @code{semctl} and +@code{semop}). +@c !!! SysV IPC is not doc'd at all in our manual + +All the semaphore functions and macros are defined in @file{semaphore.h}. + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}) +@code{sem_init} initializes the semaphore object pointed to by +@var{sem}. The count associated with the semaphore is set initially to +@var{value}. The @var{pshared} argument indicates whether the semaphore +is local to the current process (@var{pshared} is zero) or is to be +shared between several processes (@var{pshared} is not zero). + +On success @code{sem_init} returns 0. On failure it returns -1 and sets +@var{errno} to one of the following values: + +@table @code +@item EINVAL +@var{value} exceeds the maximal counter value @code{SEM_VALUE_MAX} + +@item ENOSYS +@var{pshared} is not zero. LinuxThreads currently does not support +process-shared semaphores. (This will eventually change.) +@end table +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_destroy (sem_t * @var{sem}) +@code{sem_destroy} destroys a semaphore object, freeing the resources it +might hold. If any threads are waiting on the semaphore when +@code{sem_destroy} is called, it fails and sets @var{errno} to +@code{EBUSY}. + +In the LinuxThreads implementation, no resources are associated with +semaphore objects, thus @code{sem_destroy} actually does nothing except +checking that no thread is waiting on the semaphore. This will change +when process-shared semaphores are implemented. +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_wait (sem_t * @var{sem}) +@code{sem_wait} suspends the calling thread until the semaphore pointed +to by @var{sem} has non-zero count. It then atomically decreases the +semaphore count. + +@code{sem_wait} is a cancellation point. It always returns 0. +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_trywait (sem_t * @var{sem}) +@code{sem_trywait} is a non-blocking variant of @code{sem_wait}. If the +semaphore pointed to by @var{sem} has non-zero count, the count is +atomically decreased and @code{sem_trywait} immediately returns 0. If +the semaphore count is zero, @code{sem_trywait} immediately returns -1 +and sets errno to @code{EAGAIN}. +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_post (sem_t * @var{sem}) +@code{sem_post} atomically increases the count of the semaphore pointed to +by @var{sem}. This function never blocks. + +@c !!! This para appears not to agree with the code. +On processors supporting atomic compare-and-swap (Intel 486, Pentium and +later, Alpha, PowerPC, MIPS II, Motorola 68k, Ultrasparc), the +@code{sem_post} function is can safely be called from signal handlers. +This is the only thread synchronization function provided by POSIX +threads that is async-signal safe. On the Intel 386 and earlier Sparc +chips, the current LinuxThreads implementation of @code{sem_post} is not +async-signal safe, because the hardware does not support the required +atomic operations. + +@code{sem_post} always succeeds and returns 0, unless the semaphore +count would exceed @code{SEM_VALUE_MAX} after being incremented. In +that case @code{sem_post} returns -1 and sets @var{errno} to +@code{EINVAL}. The semaphore count is left unchanged. +@end deftypefun + +@comment semaphore.h +@comment POSIX +@deftypefun int sem_getvalue (sem_t * @var{sem}, int * @var{sval}) +@code{sem_getvalue} stores in the location pointed to by @var{sval} the +current count of the semaphore @var{sem}. It always returns 0. +@end deftypefun + +@node Thread-Specific Data +@section Thread-Specific Data + +Programs often need global or static variables that have different +values in different threads. Since threads share one memory space, this +cannot be achieved with regular variables. Thread-specific data is the +POSIX threads answer to this need. + +Each thread possesses a private memory block, the thread-specific data +area, or TSD area for short. This area is indexed by TSD keys. The TSD +area associates values of type @code{void *} to TSD keys. TSD keys are +common to all threads, but the value associated with a given TSD key can +be different in each thread. + +For concreteness, the TSD areas can be viewed as arrays of @code{void *} +pointers, TSD keys as integer indices into these arrays, and the value +of a TSD key as the value of the corresponding array element in the +calling thread. + +When a thread is created, its TSD area initially associates @code{NULL} +with all keys. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_key_create (pthread_key_t *@var{key}, void (*destr_function) (void *)) +@code{pthread_key_create} allocates a new TSD key. The key is stored in +the location pointed to by @var{key}. There is a limit of +@code{PTHREAD_KEYS_MAX} on the number of keys allocated at a given +time. The value initially associated with the returned key is +@code{NULL} in all currently executing threads. + +The @var{destr_function} argument, if not @code{NULL}, specifies a +destructor function associated with the key. When a thread terminates +via @code{pthread_exit} or by cancellation, @var{destr_function} is +called on the value associated with the key in that thread. The +@var{destr_function} is not called if a key is deleted with +@code{pthread_key_delete} or a value is changed with +@code{pthread_setspecific}. The order in which destructor functions are +called at thread termination time is unspecified. + +Before the destructor function is called, the @code{NULL} value is +associated with the key in the current thread. A destructor function +might, however, re-associate non-@code{NULL} values to that key or some +other key. To deal with this, if after all the destructors have been +called for all non-@code{NULL} values, there are still some +non-@code{NULL} values with associated destructors, then the process is +repeated. The LinuxThreads implementation stops the process after +@code{PTHREAD_DESTRUCTOR_ITERATIONS} iterations, even if some +non-@code{NULL} values with associated descriptors remain. Other +implementations may loop indefinitely. + +@code{pthread_key_create} returns 0 unless @code{PTHREAD_KEYS_MAX} keys +have already been allocated, in which case it fails and returns +@code{EAGAIN}. +@end deftypefun + + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_key_delete (pthread_key_t @var{key}) +@code{pthread_key_delete} deallocates a TSD key. It does not check +whether non-@code{NULL} values are associated with that key in the +currently executing threads, nor call the destructor function associated +with the key. + +If there is no such key @var{key}, it returns @code{EINVAL}. Otherwise +it returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setspecific (pthread_key_t @var{key}, const void *@var{pointer}) +@code{pthread_setspecific} changes the value associated with @var{key} +in the calling thread, storing the given @var{pointer} instead. + +If there is no such key @var{key}, it returns @code{EINVAL}. Otherwise +it returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun {void *} pthread_getspecific (pthread_key_t @var{key}) +@code{pthread_getspecific} returns the value currently associated with +@var{key} in the calling thread. + +If there is no such key @var{key}, it returns @code{NULL}. +@end deftypefun + +The following code fragment allocates a thread-specific array of 100 +characters, with automatic reclaimation at thread exit: + +@smallexample +/* Key for the thread-specific buffer */ +static pthread_key_t buffer_key; + +/* Once-only initialisation of the key */ +static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT; + +/* Allocate the thread-specific buffer */ +void buffer_alloc(void) +@{ + pthread_once(&buffer_key_once, buffer_key_alloc); + pthread_setspecific(buffer_key, malloc(100)); +@} + +/* Return the thread-specific buffer */ +char * get_buffer(void) +@{ + return (char *) pthread_getspecific(buffer_key); +@} + +/* Allocate the key */ +static void buffer_key_alloc() +@{ + pthread_key_create(&buffer_key, buffer_destroy); +@} + +/* Free the thread-specific buffer */ +static void buffer_destroy(void * buf) +@{ + free(buf); +@} +@end smallexample + +@node Threads and Signal Handling +@section Threads and Signal Handling + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_sigmask (int @var{how}, const sigset_t *@var{newmask}, sigset_t *@var{oldmask}) +@code{pthread_sigmask} changes the signal mask for the calling thread as +described by the @var{how} and @var{newmask} arguments. If @var{oldmask} +is not @code{NULL}, the previous signal mask is stored in the location +pointed to by @var{oldmask}. + +The meaning of the @var{how} and @var{newmask} arguments is the same as +for @code{sigprocmask}. If @var{how} is @code{SIG_SETMASK}, the signal +mask is set to @var{newmask}. If @var{how} is @code{SIG_BLOCK}, the +signals specified to @var{newmask} are added to the current signal mask. +If @var{how} is @code{SIG_UNBLOCK}, the signals specified to +@var{newmask} are removed from the current signal mask. + +Recall that signal masks are set on a per-thread basis, but signal +actions and signal handlers, as set with @code{sigaction}, are shared +between all threads. + +The @code{pthread_sigmask} function returns 0 on success, and one of the +following error codes on error: +@table @code +@item EINVAL +@var{how} is not one of @code{SIG_SETMASK}, @code{SIG_BLOCK}, or @code{SIG_UNBLOCK} + +@item EFAULT +@var{newmask} or @var{oldmask} point to invalid addresses +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_kill (pthread_t @var{thread}, int @var{signo}) +@code{pthread_kill} sends signal number @var{signo} to the thread +@var{thread}. The signal is delivered and handled as described in +@ref{Signal Handling}. + +@code{pthread_kill} returns 0 on success, one of the following error codes +on error: +@table @code +@item EINVAL +@var{signo} is not a valid signal number + +@item ESRCH +The thread @var{thread} does not exist (e.g. it has already terminated) +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int sigwait (const sigset_t *@var{set}, int *@var{sig}) +@code{sigwait} suspends the calling thread until one of the signals in +@var{set} is delivered to the calling thread. It then stores the number +of the signal received in the location pointed to by @var{sig} and +returns. The signals in @var{set} must be blocked and not ignored on +entrance to @code{sigwait}. If the delivered signal has a signal handler +function attached, that function is @emph{not} called. + +@code{sigwait} is a cancellation point. It always returns 0. +@end deftypefun + +For @code{sigwait} to work reliably, the signals being waited for must be +blocked in all threads, not only in the calling thread, since +otherwise the POSIX semantics for signal delivery do not guarantee +that it's the thread doing the @code{sigwait} that will receive the signal. +The best way to achieve this is block those signals before any threads +are created, and never unblock them in the program other than by +calling @code{sigwait}. + +Signal handling in LinuxThreads departs significantly from the POSIX +standard. According to the standard, ``asynchronous'' (external) signals +are addressed to the whole process (the collection of all threads), +which then delivers them to one particular thread. The thread that +actually receives the signal is any thread that does not currently block +the signal. + +In LinuxThreads, each thread is actually a kernel process with its own +PID, so external signals are always directed to one particular thread. +If, for instance, another thread is blocked in @code{sigwait} on that +signal, it will not be restarted. + +The LinuxThreads implementation of @code{sigwait} installs dummy signal +handlers for the signals in @var{set} for the duration of the +wait. Since signal handlers are shared between all threads, other +threads must not attach their own signal handlers to these signals, or +alternatively they should all block these signals (which is recommended +anyway). + +@node Threads and Fork +@section Threads and Fork + +It's not intuitively obvious what should happen when a multi-threaded POSIX +process calls @code{fork}. Not only are the semantics tricky, but you may +need to write code that does the right thing at fork time even if that code +doesn't use the @code{fork} function. Moreover, you need to be aware of +interaction between @code{fork} and some library features like +@code{pthread_once} and stdio streams. + +When @code{fork} is called by one of the threads of a process, it creates a new +process which is copy of the calling process. Effectively, in addition to +copying certain system objects, the function takes a snapshot of the memory +areas of the parent process, and creates identical areas in the child. +To make matters more complicated, with threads it's possible for two or more +threads to concurrently call fork to create two or more child processes. + +The child process has a copy of the address space of the parent, but it does +not inherit any of its threads. Execution of the child process is carried out +by a new thread which returns from @code{fork} function with a return value of +zero; it is the only thread in the child process. Because threads are not +inherited across fork, issues arise. At the time of the call to @code{fork}, +threads in the parent process other than the one calling @code{fork} may have +been executing critical regions of code. As a result, the child process may +get a copy of objects that are not in a well-defined state. This potential +problem affects all components of the program. + +Any program component which will continue being used in a child process must +correctly handle its state during @code{fork}. For this purpose, the POSIX +interface provides the special function @code{pthread_atfork} for installing +pointers to handler functions which are called from within @code{fork}. + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_atfork (void (*@var{prepare})(void), void (*@var{parent})(void), void (*@var{child})(void)) + +@code{pthread_atfork} registers handler functions to be called just +before and just after a new process is created with @code{fork}. The +@var{prepare} handler will be called from the parent process, just +before the new process is created. The @var{parent} handler will be +called from the parent process, just before @code{fork} returns. The +@var{child} handler will be called from the child process, just before +@code{fork} returns. + +@code{pthread_atfork} returns 0 on success and a non-zero error code on +error. + +One or more of the three handlers @var{prepare}, @var{parent} and +@var{child} can be given as @code{NULL}, meaning that no handler needs +to be called at the corresponding point. + +@code{pthread_atfork} can be called several times to install several +sets of handlers. At @code{fork} time, the @var{prepare} handlers are +called in LIFO order (last added with @code{pthread_atfork}, first +called before @code{fork}), while the @var{parent} and @var{child} +handlers are called in FIFO order (first added, first called). + +If there is insufficient memory available to register the handlers, +@code{pthread_atfork} fails and returns @code{ENOMEM}. Otherwise it +returns 0. + +The functions @code{fork} and @code{pthread_atfork} must not be regarded as +reentrant from the context of the handlers. That is to say, if a +@code{pthread_atfork} handler invoked from within @code{fork} calls +@code{pthread_atfork} or @code{fork}, the behavior is undefined. + +Registering a triplet of handlers is an atomic operation with respect to fork. +If new handlers are registered at about the same time as a fork occurs, either +all three handlers will be called, or none of them will be called. + +The handlers are inherited by the child process, and there is no +way to remove them, short of using @code{exec} to load a new +pocess image. + +@end deftypefun + +To understand the purpose of @code{pthread_atfork}, recall that +@code{fork} duplicates the whole memory space, including mutexes in +their current locking state, but only the calling thread: other threads +are not running in the child process. The mutexes are not usable after +the @code{fork} and must be initialized with @code{pthread_mutex_init} +in the child process. This is a limitation of the current +implementation and might or might not be present in future versions. + +To avoid this, install handlers with @code{pthread_atfork} as follows: have the +@var{prepare} handler lock the mutexes (in locking order), and the +@var{parent} handler unlock the mutexes. The @var{child} handler should reset +the mutexes using @code{pthread_mutex_init}, as well as any other +synchronization objects such as condition variables. + +Locking the global mutexes before the fork ensures that all other threads are +locked out of the critical regions of code protected by those mutexes. Thus +when @code{fork} takes a snapshot of the parent's address space, that snapshot +will copy valid, stable data. Resetting the synchronization objects in the +child process will ensure they are properly cleansed of any artifacts from the +threading subsystem of the parent process. For example, a mutex may inherit +a wait queue of threads waiting for the lock; this wait queue makes no sense +in the child process. Initializing the mutex takes care of this. + +@node Streams and Fork +@section Streams and Fork + +The GNU standard I/O library has an internal mutex which guards the internal +linked list of all standard C FILE objects. This mutex is properly taken care +of during @code{fork} so that the child receives an intact copy of the list. +This allows the @code{fopen} function, and related stream-creating functions, +to work correctly in the child process, since these functions need to insert +into the list. + +However, the individual stream locks are not completely taken care of. Thus +unless the multithreaded application takes special precautions in its use of +@code{fork}, the child process might not be able to safely use the streams that +it inherited from the parent. In general, for any given open stream in the +parent that is to be used by the child process, the application must ensure +that that stream is not in use by another thread when @code{fork} is called. +Otherwise an inconsistent copy of the stream object be produced. An easy way to +ensure this is to use @code{flockfile} to lock the stream prior to calling +@code{fork} and then unlock it with @code{funlockfile} inside the parent +process, provided that the parent's threads properly honor these locks. +Nothing special needs to be done in the child process, since the library +internally resets all stream locks. + +Note that the stream locks are not shared between the parent and child. +For example, even if you ensure that, say, the stream @code{stdout} is properly +treated and can be safely used in the child, the stream locks do not provide +an exclusion mechanism between the parent and child. If both processes write +to @code{stdout}, strangely interleaved output may result regardless of +the explicit use of @code{flockfile} or implicit locks. + +Also note that these provisions are a GNU extension; other systems might not +provide any way for streams to be used in the child of a multithreaded process. +POSIX requires that such a child process confines itself to calling only +asynchronous safe functions, which excludes much of the library, including +standard I/O. + +@node Miscellaneous Thread Functions +@section Miscellaneous Thread Functions + +@comment pthread.h +@comment POSIX +@deftypefun {pthread_t} pthread_self (@var{void}) +@code{pthread_self} returns the thread identifier for the calling thread. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_equal (pthread_t thread1, pthread_t thread2) +@code{pthread_equal} determines if two thread identifiers refer to the same +thread. + +A non-zero value is returned if @var{thread1} and @var{thread2} refer to +the same thread. Otherwise, 0 is returned. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_detach (pthread_t @var{th}) +@code{pthread_detach} puts the thread @var{th} in the detached +state. This guarantees that the memory resources consumed by @var{th} +will be freed immediately when @var{th} terminates. However, this +prevents other threads from synchronizing on the termination of @var{th} +using @code{pthread_join}. + +A thread can be created initially in the detached state, using the +@code{detachstate} attribute to @code{pthread_create}. In contrast, +@code{pthread_detach} applies to threads created in the joinable state, +and which need to be put in the detached state later. + +After @code{pthread_detach} completes, subsequent attempts to perform +@code{pthread_join} on @var{th} will fail. If another thread is already +joining the thread @var{th} at the time @code{pthread_detach} is called, +@code{pthread_detach} does nothing and leaves @var{th} in the joinable +state. + +On success, 0 is returned. On error, one of the following codes is +returned: +@table @code +@item ESRCH +No thread could be found corresponding to that specified by @var{th} +@item EINVAL +The thread @var{th} is already in the detached state +@end table +@end deftypefun + +@comment pthread.h +@comment GNU +@deftypefun void pthread_kill_other_threads_np (@var{void}) +@code{pthread_kill_other_threads_np} is a non-portable LinuxThreads extension. +It causes all threads in the program to terminate immediately, except +the calling thread which proceeds normally. It is intended to be +called just before a thread calls one of the @code{exec} functions, +e.g. @code{execve}. + +Termination of the other threads is not performed through +@code{pthread_cancel} and completely bypasses the cancellation +mechanism. Hence, the current settings for cancellation state and +cancellation type are ignored, and the cleanup handlers are not +executed in the terminated threads. + +According to POSIX 1003.1c, a successful @code{exec*} in one of the +threads should automatically terminate all other threads in the program. +This behavior is not yet implemented in LinuxThreads. Calling +@code{pthread_kill_other_threads_np} before @code{exec*} achieves much +of the same behavior, except that if @code{exec*} ultimately fails, then +all other threads are already killed. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_once (pthread_once_t *once_@var{control}, void (*@var{init_routine}) (void)) + +The purpose of @code{pthread_once} is to ensure that a piece of +initialization code is executed at most once. The @var{once_control} +argument points to a static or extern variable statically initialized +to @code{PTHREAD_ONCE_INIT}. + +The first time @code{pthread_once} is called with a given +@var{once_control} argument, it calls @var{init_routine} with no +argument and changes the value of the @var{once_control} variable to +record that initialization has been performed. Subsequent calls to +@code{pthread_once} with the same @code{once_control} argument do +nothing. + +If a thread is cancelled while executing @var{init_routine} +the state of the @var{once_control} variable is reset so that +a future call to @code{pthread_once} will call the routine again. + +If the process forks while one or more threads are executing +@code{pthread_once} initialization routines, the states of their respective +@var{once_control} variables will appear to be reset in the child process so +that if the child calls @code{pthread_once}, the routines will be executed. + +@code{pthread_once} always returns 0. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setschedparam (pthread_t target_@var{thread}, int @var{policy}, const struct sched_param *@var{param}) + +@code{pthread_setschedparam} sets the scheduling parameters for the +thread @var{target_thread} as indicated by @var{policy} and +@var{param}. @var{policy} can be either @code{SCHED_OTHER} (regular, +non-realtime scheduling), @code{SCHED_RR} (realtime, round-robin) or +@code{SCHED_FIFO} (realtime, first-in first-out). @var{param} specifies +the scheduling priority for the two realtime policies. See +@code{sched_setpolicy} for more information on scheduling policies. + +The realtime scheduling policies @code{SCHED_RR} and @code{SCHED_FIFO} +are available only to processes with superuser privileges. + +On success, @code{pthread_setschedparam} returns 0. On error it returns +one of the following codes: +@table @code +@item EINVAL +@var{policy} is not one of @code{SCHED_OTHER}, @code{SCHED_RR}, +@code{SCHED_FIFO}, or the priority value specified by @var{param} is not +valid for the specified policy + +@item EPERM +Realtime scheduling was requested but the calling process does not have +sufficient privileges. + +@item ESRCH +The @var{target_thread} is invalid or has already terminated + +@item EFAULT +@var{param} points outside the process memory space +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_getschedparam (pthread_t target_@var{thread}, int *@var{policy}, struct sched_param *@var{param}) + +@code{pthread_getschedparam} retrieves the scheduling policy and +scheduling parameters for the thread @var{target_thread} and stores them +in the locations pointed to by @var{policy} and @var{param}, +respectively. + +@code{pthread_getschedparam} returns 0 on success, or one of the +following error codes on failure: +@table @code +@item ESRCH +The @var{target_thread} is invalid or has already terminated. + +@item EFAULT +@var{policy} or @var{param} point outside the process memory space. + +@end table +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_setconcurrency (int @var{level}) +@code{pthread_setconcurrency} is unused in LinuxThreads due to the lack +of a mapping of user threads to kernel threads. It exists for source +compatibility. It does store the value @var{level} so that it can be +returned by a subsequent call to @code{pthread_getconcurrency}. It takes +no other action however. +@end deftypefun + +@comment pthread.h +@comment POSIX +@deftypefun int pthread_getconcurrency () +@code{pthread_getconcurrency} is unused in LinuxThreads due to the lack +of a mapping of user threads to kernel threads. It exists for source +compatibility. However, it will return the value that was set by the +last call to @code{pthread_setconcurrency}. +@end deftypefun diff --git a/libpthread/linuxthreads.old/locale.c b/libpthread/linuxthreads.old/locale.c new file mode 100644 index 000000000..c3ebbc285 --- /dev/null +++ b/libpthread/linuxthreads.old/locale.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2003 Manuel Novoa III + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define _GNU_SOURCE +#include +#include "pthread.h" +#include "internals.h" +#include +#include +#include + +extern struct _pthread_descr_struct __pthread_initial_thread; + +__locale_t __curlocale(void) +{ + pthread_descr self = thread_self(); + +#ifdef NDEBUG + return THREAD_GETMEM (self, locale); +#else + { + __locale_t r = THREAD_GETMEM (self, locale); + + assert(r); + + return r; + } +#endif +} + +__locale_t __curlocale_set(__locale_t newloc) +{ + __locale_t oldloc; + pthread_descr self = thread_self(); + + oldloc = THREAD_GETMEM (self, locale); + + assert(newloc != LC_GLOBAL_LOCALE); + assert(oldloc); + + THREAD_SETMEM (self, locale, newloc); + + return oldloc; +} diff --git a/libpthread/linuxthreads.old/lockfile.c b/libpthread/linuxthreads.old/lockfile.c new file mode 100644 index 000000000..b0f41c98a --- /dev/null +++ b/libpthread/linuxthreads.old/lockfile.c @@ -0,0 +1,39 @@ +/* lockfile - Handle locking and unlocking of stream. + Copyright (C) 1996, 1998, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include + +/* Note: glibc puts flockfile, funlockfile, and ftrylockfile in both + * libc and libpthread. In uClibc, they are now in libc only. */ + +void +__fresetlockfiles (void) +{ + FILE *fp; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); + + for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) + pthread_mutex_init(&fp->__lock, &attr); + + pthread_mutexattr_destroy(&attr); +} diff --git a/libpthread/linuxthreads.old/manager.c b/libpthread/linuxthreads.old/manager.c new file mode 100644 index 000000000..204344aef --- /dev/null +++ b/libpthread/linuxthreads.old/manager.c @@ -0,0 +1,905 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* The "thread manager" thread: manages creation and termination of threads */ + +/* mods for uClibc: getpwd and getpagesize are the syscalls */ +#define __getpid getpid +#define __getpagesize getpagesize + +#include +#define __USE_GNU +#include +#include +#include +#include +#include +#include +#include +#include /* for poll */ +#include /* for mmap */ +#include +#include +#include /* for waitpid macros */ + +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "semaphore.h" +#include "debug.h" /* PDEBUG, added by StS */ + + +/* poll() is not supported in kernel <= 2.0, therefore is __NR_poll is + * not available, we assume an old Linux kernel is in use and we will + * use select() instead. */ +#include +#ifndef __NR_poll +# define USE_SELECT +#endif + + +/* Array of active threads. Entry 0 is reserved for the initial thread. */ +struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] = +{ { __LOCK_INITIALIZER, &__pthread_initial_thread, 0}, + { __LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ }; + +/* For debugging purposes put the maximum number of threads in a variable. */ +const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX; + +/* Indicate whether at least one thread has a user-defined stack (if 1), + or if all threads have stacks supplied by LinuxThreads (if 0). */ +int __pthread_nonstandard_stacks; + +/* Number of active entries in __pthread_handles (used by gdb) */ +volatile int __pthread_handles_num = 2; + +/* Whether to use debugger additional actions for thread creation + (set to 1 by gdb) */ +volatile int __pthread_threads_debug; + +/* Globally enabled events. */ +volatile td_thr_events_t __pthread_threads_events; + +/* Pointer to thread descriptor with last event. */ +volatile pthread_descr __pthread_last_event; + +/* Mapping from stack segment to thread descriptor. */ +/* Stack segment numbers are also indices into the __pthread_handles array. */ +/* Stack segment number 0 is reserved for the initial thread. */ + +static inline pthread_descr thread_segment(int seg) +{ + return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE) + - 1; +} + +/* Flag set in signal handler to record child termination */ + +static volatile int terminated_children = 0; + +/* Flag set when the initial thread is blocked on pthread_exit waiting + for all other threads to terminate */ + +static int main_thread_exiting = 0; + +/* Counter used to generate unique thread identifier. + Thread identifier is pthread_threads_counter + segment. */ + +static pthread_t pthread_threads_counter = 0; + +/* Forward declarations */ + +static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg, + sigset_t *mask, int father_pid, + int report_events, + td_thr_events_t *event_maskp); +static void pthread_handle_free(pthread_t th_id); +static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode); +static void pthread_reap_children(void); +static void pthread_kill_all_threads(int sig, int main_thread_also); + +/* The server thread managing requests for thread creation and termination */ + +int __pthread_manager(void *arg) +{ + int reqfd = (int) (long int) arg; +#ifdef USE_SELECT + struct timeval tv; + fd_set fd; +#else + struct pollfd ufd; +#endif + sigset_t manager_mask; + int n; + struct pthread_request request; + + /* If we have special thread_self processing, initialize it. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(&__pthread_manager_thread, 1); +#endif + /* Set the error variable. */ + __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno; + __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno; + +#ifdef __UCLIBC_HAS_XLOCALE__ + /* Initialize thread's locale to the global locale. */ + __pthread_manager_thread.locale = __global_locale; +#endif /* __UCLIBC_HAS_XLOCALE__ */ + + /* Block all signals except __pthread_sig_cancel and SIGTRAP */ + sigfillset(&manager_mask); + sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */ + sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */ + if (__pthread_threads_debug && __pthread_sig_debug > 0) + sigdelset(&manager_mask, __pthread_sig_debug); + sigprocmask(SIG_SETMASK, &manager_mask, NULL); + /* Raise our priority to match that of main thread */ + __pthread_manager_adjust_prio(__pthread_main_thread->p_priority); + /* Synchronize debugging of the thread manager */ + n = TEMP_FAILURE_RETRY(__libc_read(reqfd, (char *)&request, + sizeof(request))); + ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG); +#ifndef USE_SELECT + ufd.fd = reqfd; + ufd.events = POLLIN; +#endif + /* Enter server loop */ + while(1) { +#ifdef USE_SELECT + tv.tv_sec = 2; + tv.tv_usec = 0; + FD_ZERO (&fd); + FD_SET (reqfd, &fd); + n = select (reqfd + 1, &fd, NULL, NULL, &tv); +#else + PDEBUG("before poll\n"); + n = poll(&ufd, 1, 2000); + PDEBUG("after poll\n"); +#endif + /* Check for termination of the main thread */ + if (getppid() == 1) { + pthread_kill_all_threads(SIGKILL, 0); + _exit(0); + } + /* Check for dead children */ + if (terminated_children) { + terminated_children = 0; + pthread_reap_children(); + } + /* Read and execute request */ +#ifdef USE_SELECT + if (n == 1) +#else + if (n == 1 && (ufd.revents & POLLIN)) +#endif + { + + PDEBUG("before __libc_read\n"); + n = __libc_read(reqfd, (char *)&request, sizeof(request)); + PDEBUG("after __libc_read, n=%d\n", n); + ASSERT(n == sizeof(request)); + switch(request.req_kind) { + case REQ_CREATE: + PDEBUG("got REQ_CREATE\n"); + request.req_thread->p_retcode = + pthread_handle_create((pthread_t *) &request.req_thread->p_retval, + request.req_args.create.attr, + request.req_args.create.fn, + request.req_args.create.arg, + &request.req_args.create.mask, + request.req_thread->p_pid, + request.req_thread->p_report_events, + &request.req_thread->p_eventbuf.eventmask); + PDEBUG("restarting %d\n", request.req_thread); + restart(request.req_thread); + break; + case REQ_FREE: + PDEBUG("got REQ_FREE\n"); + pthread_handle_free(request.req_args.free.thread_id); + break; + case REQ_PROCESS_EXIT: + PDEBUG("got REQ_PROCESS_EXIT from %d, exit code = %d\n", + request.req_thread, request.req_args.exit.code); + pthread_handle_exit(request.req_thread, + request.req_args.exit.code); + break; + case REQ_MAIN_THREAD_EXIT: + PDEBUG("got REQ_MAIN_THREAD_EXIT\n"); + main_thread_exiting = 1; + /* Reap children in case all other threads died and the signal handler + went off before we set main_thread_exiting to 1, and therefore did + not do REQ_KICK. */ + pthread_reap_children(); + + if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { + restart(__pthread_main_thread); + /* The main thread will now call exit() which will trigger an + __on_exit handler, which in turn will send REQ_PROCESS_EXIT + to the thread manager. In case you are wondering how the + manager terminates from its loop here. */ + } + break; + case REQ_POST: + PDEBUG("got REQ_POST\n"); + __new_sem_post(request.req_args.post); + break; + case REQ_DEBUG: + PDEBUG("got REQ_DEBUG\n"); + /* Make gdb aware of new thread and gdb will restart the + new thread when it is ready to handle the new thread. */ + if (__pthread_threads_debug && __pthread_sig_debug > 0) { + PDEBUG("about to call raise(__pthread_sig_debug)\n"); + raise(__pthread_sig_debug); + } + case REQ_KICK: + /* This is just a prod to get the manager to reap some + threads right away, avoiding a potential delay at shutdown. */ + break; + } + } + } +} + +int __pthread_manager_event(void *arg) +{ + /* If we have special thread_self processing, initialize it. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(&__pthread_manager_thread, 1); +#endif + + /* Get the lock the manager will free once all is correctly set up. */ + __pthread_lock (THREAD_GETMEM((&__pthread_manager_thread), p_lock), NULL); + /* Free it immediately. */ + __pthread_unlock (THREAD_GETMEM((&__pthread_manager_thread), p_lock)); + + return __pthread_manager(arg); +} + +/* Process creation */ +static int +__attribute__ ((noreturn)) +pthread_start_thread(void *arg) +{ + pthread_descr self = (pthread_descr) arg; + struct pthread_request request; + void * outcome; + /* Initialize special thread_self processing, if any. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(self, self->p_nr); +#endif + PDEBUG("\n"); + /* Make sure our pid field is initialized, just in case we get there + before our father has initialized it. */ + THREAD_SETMEM(self, p_pid, __getpid()); + /* Initial signal mask is that of the creating thread. (Otherwise, + we'd just inherit the mask of the thread manager.) */ + sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); + /* Set the scheduling policy and priority for the new thread, if needed */ + if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) + /* Explicit scheduling attributes were provided: apply them */ + sched_setscheduler(THREAD_GETMEM(self, p_pid), + THREAD_GETMEM(self, p_start_args.schedpolicy), + &self->p_start_args.schedparam); + else if (__pthread_manager_thread.p_priority > 0) + /* Default scheduling required, but thread manager runs in realtime + scheduling: switch new thread to SCHED_OTHER policy */ + { + struct sched_param default_params; + default_params.sched_priority = 0; + sched_setscheduler(THREAD_GETMEM(self, p_pid), + SCHED_OTHER, &default_params); + } + /* Make gdb aware of new thread */ + if (__pthread_threads_debug && __pthread_sig_debug > 0) { + request.req_thread = self; + request.req_kind = REQ_DEBUG; + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); + suspend(self); + } + /* Run the thread code */ + outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, + p_start_args.arg)); + /* Exit with the given return value */ + pthread_exit(outcome); +} + +static int +__attribute__ ((noreturn)) +pthread_start_thread_event(void *arg) +{ + pthread_descr self = (pthread_descr) arg; + +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(self, self->p_nr); +#endif + /* Make sure our pid field is initialized, just in case we get there + before our father has initialized it. */ + THREAD_SETMEM(self, p_pid, __getpid()); + /* Get the lock the manager will free once all is correctly set up. */ + __pthread_lock (THREAD_GETMEM(self, p_lock), NULL); + /* Free it immediately. */ + __pthread_unlock (THREAD_GETMEM(self, p_lock)); + + /* Continue with the real function. */ + pthread_start_thread (arg); +} + +static int pthread_allocate_stack(const pthread_attr_t *attr, + pthread_descr default_new_thread, + int pagesize, + pthread_descr * out_new_thread, + char ** out_new_thread_bottom, + char ** out_guardaddr, + size_t * out_guardsize) +{ + pthread_descr new_thread; + char * new_thread_bottom; + char * guardaddr; + size_t stacksize, guardsize; + + if (attr != NULL && attr->__stackaddr_set) + { + /* The user provided a stack. */ + new_thread = + (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1; + new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize; + guardaddr = NULL; + guardsize = 0; + __pthread_nonstandard_stacks = 1; + } + else + { +#ifdef __ARCH_HAS_MMU__ + stacksize = STACK_SIZE - pagesize; + if (attr != NULL) + stacksize = MIN (stacksize, roundup(attr->__stacksize, pagesize)); + /* Allocate space for stack and thread descriptor at default address */ + new_thread = default_new_thread; + new_thread_bottom = (char *) (new_thread + 1) - stacksize; + if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE), + INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, + -1, 0) == MAP_FAILED) + /* Bad luck, this segment is already mapped. */ + return -1; + /* We manage to get a stack. Now see whether we need a guard + and allocate it if necessary. Notice that the default + attributes (stack_size = STACK_SIZE - pagesize) do not need + a guard page, since the RLIMIT_STACK soft limit prevents stacks + from running into one another. */ + if (stacksize == STACK_SIZE - pagesize) + { + /* We don't need a guard page. */ + guardaddr = NULL; + guardsize = 0; + } + else + { + /* Put a bad page at the bottom of the stack */ + guardsize = attr->__guardsize; + guardaddr = (void *)new_thread_bottom - guardsize; + if (mmap ((caddr_t) guardaddr, guardsize, 0, MAP_FIXED, -1, 0) + == MAP_FAILED) + { + /* We don't make this an error. */ + guardaddr = NULL; + guardsize = 0; + } + } +#else + /* We cannot mmap to this huge chunk of stack space when we don't have + * an MMU. Pretend we are using a user provided stack even if there was + * none provided by the user. Thus, we get around the mmap and reservation + * of a huge stack segment. -StS */ + + stacksize = INITIAL_STACK_SIZE; + /* The user may want to use a non-default stacksize */ + if (attr != NULL) + { + stacksize = attr->__stacksize; + } + + /* malloc a stack - memory from the bottom up */ + if ((new_thread_bottom = malloc(stacksize)) == NULL) + { + /* bad luck, we cannot malloc any more */ + return -1 ; + } + PDEBUG("malloced chunk: base=%p, size=0x%04x\n", new_thread_bottom, stacksize); + + /* Set up the pointers. new_thread marks the TOP of the stack frame and + * the address of the pthread_descr struct at the same time. Therefore we + * must account for its size and fit it in the malloc()'ed block. The + * value of `new_thread' is then passed to clone() as the stack argument. + * + * ^ +------------------------+ + * | | pthread_descr struct | + * | +------------------------+ <- new_thread + * malloc block | | | + * | | thread stack | + * | | | + * v +------------------------+ <- new_thread_bottom + * + * Note: The calculated value of new_thread must be word aligned otherwise + * the kernel chokes on a non-aligned stack frame. Choose the lower + * available word boundary. + */ + new_thread = ((pthread_descr) ((int)(new_thread_bottom + stacksize) & -sizeof(void*))) - 1; + guardaddr = NULL; + guardsize = 0; + + PDEBUG("thread stack: bos=%p, tos=%p\n", new_thread_bottom, new_thread); + + /* check the initial thread stack boundaries so they don't overlap */ + NOMMU_INITIAL_THREAD_BOUNDS((char *) new_thread, (char *) new_thread_bottom); + + PDEBUG("initial stack: bos=%p, tos=%p\n", __pthread_initial_thread_bos, + __pthread_initial_thread_tos); + + /* on non-MMU systems we always have non-standard stack frames */ + __pthread_nonstandard_stacks = 1; + +#endif /* __ARCH_HAS_MMU__ */ + } + + /* Clear the thread data structure. */ + memset (new_thread, '\0', sizeof (*new_thread)); + *out_new_thread = new_thread; + *out_new_thread_bottom = new_thread_bottom; + *out_guardaddr = guardaddr; + *out_guardsize = guardsize; + return 0; +} + +static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg, + sigset_t * mask, int father_pid, + int report_events, + td_thr_events_t *event_maskp) +{ + size_t sseg; + int pid; + pthread_descr new_thread; + char * new_thread_bottom; + pthread_t new_thread_id; + char *guardaddr = NULL; + size_t guardsize = 0; + int pagesize = __getpagesize(); + int saved_errno = 0; + + /* First check whether we have to change the policy and if yes, whether + we can do this. Normally this should be done by examining the + return value of the sched_setscheduler call in pthread_start_thread + but this is hard to implement. FIXME */ + if (attr != NULL && attr->__schedpolicy != SCHED_OTHER && geteuid () != 0) + return EPERM; + /* Find a free segment for the thread, and allocate a stack if needed */ + for (sseg = 2; ; sseg++) + { + if (sseg >= PTHREAD_THREADS_MAX) + return EAGAIN; + if (__pthread_handles[sseg].h_descr != NULL) + continue; + if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize, + &new_thread, &new_thread_bottom, + &guardaddr, &guardsize) == 0) + break; + } + __pthread_handles_num++; + /* Allocate new thread identifier */ + pthread_threads_counter += PTHREAD_THREADS_MAX; + new_thread_id = sseg + pthread_threads_counter; + /* Initialize the thread descriptor. Elements which have to be + initialized to zero already have this value. */ + new_thread->p_tid = new_thread_id; + new_thread->p_lock = &(__pthread_handles[sseg].h_lock); + new_thread->p_cancelstate = PTHREAD_CANCEL_ENABLE; + new_thread->p_canceltype = PTHREAD_CANCEL_DEFERRED; + new_thread->p_errnop = &new_thread->p_errno; + new_thread->p_h_errnop = &new_thread->p_h_errno; +#ifdef __UCLIBC_HAS_XLOCALE__ + /* Initialize thread's locale to the global locale. */ + new_thread->locale = __global_locale; +#endif /* __UCLIBC_HAS_XLOCALE__ */ + new_thread->p_guardaddr = guardaddr; + new_thread->p_guardsize = guardsize; + new_thread->p_self = new_thread; + new_thread->p_nr = sseg; + /* Initialize the thread handle */ + __pthread_init_lock(&__pthread_handles[sseg].h_lock); + __pthread_handles[sseg].h_descr = new_thread; + __pthread_handles[sseg].h_bottom = new_thread_bottom; + /* Determine scheduling parameters for the thread */ + new_thread->p_start_args.schedpolicy = -1; + if (attr != NULL) { + new_thread->p_detached = attr->__detachstate; + new_thread->p_userstack = attr->__stackaddr_set; + + switch(attr->__inheritsched) { + case PTHREAD_EXPLICIT_SCHED: + new_thread->p_start_args.schedpolicy = attr->__schedpolicy; + memcpy (&new_thread->p_start_args.schedparam, &attr->__schedparam, + sizeof (struct sched_param)); + break; + case PTHREAD_INHERIT_SCHED: + new_thread->p_start_args.schedpolicy = sched_getscheduler(father_pid); + sched_getparam(father_pid, &new_thread->p_start_args.schedparam); + break; + } + new_thread->p_priority = + new_thread->p_start_args.schedparam.sched_priority; + } + /* Finish setting up arguments to pthread_start_thread */ + new_thread->p_start_args.start_routine = start_routine; + new_thread->p_start_args.arg = arg; + new_thread->p_start_args.mask = *mask; + /* Raise priority of thread manager if needed */ + __pthread_manager_adjust_prio(new_thread->p_priority); + /* Do the cloning. We have to use two different functions depending + on whether we are debugging or not. */ + pid = 0; /* Note that the thread never can have PID zero. */ + + + /* ******************************************************** */ + /* This code was moved from below to cope with running threads + * on uClinux systems. See comment below... + * Insert new thread in doubly linked list of active threads */ + new_thread->p_prevlive = __pthread_main_thread; + new_thread->p_nextlive = __pthread_main_thread->p_nextlive; + __pthread_main_thread->p_nextlive->p_prevlive = new_thread; + __pthread_main_thread->p_nextlive = new_thread; + /* ********************************************************* */ + + if (report_events) + { + /* See whether the TD_CREATE event bit is set in any of the + masks. */ + int idx = __td_eventword (TD_CREATE); + uint32_t mask = __td_eventmask (TD_CREATE); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | event_maskp->event_bits[idx])) != 0) + { + /* Lock the mutex the child will use now so that it will stop. */ + __pthread_lock(new_thread->p_lock, NULL); + + /* We have to report this event. */ + pid = clone(pthread_start_thread_event, (void **) new_thread, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); + + saved_errno = errno; + if (pid != -1) + { + /* Now fill in the information about the new thread in + the newly created thread's data structure. We cannot let + the new thread do this since we don't know whether it was + already scheduled when we send the event. */ + new_thread->p_eventbuf.eventdata = new_thread; + new_thread->p_eventbuf.eventnum = TD_CREATE; + __pthread_last_event = new_thread; + + /* We have to set the PID here since the callback function + in the debug library will need it and we cannot guarantee + the child got scheduled before the debugger. */ + new_thread->p_pid = pid; + + /* Now call the function which signals the event. */ + __linuxthreads_create_event (); + + /* Now restart the thread. */ + __pthread_unlock(new_thread->p_lock); + } + } + } + if (pid == 0) + { + PDEBUG("cloning new_thread = %p\n", new_thread); + pid = clone(pthread_start_thread, (void **) new_thread, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + __pthread_sig_cancel, new_thread); + saved_errno = errno; + } + /* Check if cloning succeeded */ + if (pid == -1) { + /******************************************************** + * Code inserted to remove the thread from our list of active + * threads in case of failure (needed to cope with uClinux), + * See comment below. */ + new_thread->p_nextlive->p_prevlive = new_thread->p_prevlive; + new_thread->p_prevlive->p_nextlive = new_thread->p_nextlive; + /********************************************************/ + + /* Free the stack if we allocated it */ + if (attr == NULL || !attr->__stackaddr_set) + { +#ifdef __ARCH_HAS_MMU__ + if (new_thread->p_guardsize != 0) + munmap(new_thread->p_guardaddr, new_thread->p_guardsize); + munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE), + INITIAL_STACK_SIZE); +#else + free(new_thread_bottom); +#endif /* __ARCH_HAS_MMU__ */ + } + __pthread_handles[sseg].h_descr = NULL; + __pthread_handles[sseg].h_bottom = NULL; + __pthread_handles_num--; + return errno; + } + PDEBUG("new thread pid = %d\n", pid); + +#if 0 + /* *********************************************************** + This code has been moved before the call to clone(). In uClinux, + the use of wait on a semaphore is dependant upon that the child so + the child must be in the active threads list. This list is used in + pthread_find_self() to get the pthread_descr of self. So, if the + child calls sem_wait before this code is executed , it will hang + forever and initial_thread will instead be posted by a sem_post + call. */ + + /* Insert new thread in doubly linked list of active threads */ + new_thread->p_prevlive = __pthread_main_thread; + new_thread->p_nextlive = __pthread_main_thread->p_nextlive; + __pthread_main_thread->p_nextlive->p_prevlive = new_thread; + __pthread_main_thread->p_nextlive = new_thread; + /************************************************************/ +#endif + + /* Set pid field of the new thread, in case we get there before the + child starts. */ + new_thread->p_pid = pid; + /* We're all set */ + *thread = new_thread_id; + return 0; +} + + +/* Try to free the resources of a thread when requested by pthread_join + or pthread_detach on a terminated thread. */ + +static void pthread_free(pthread_descr th) +{ + pthread_handle handle; + pthread_readlock_info *iter, *next; + char *h_bottom_save; + + ASSERT(th->p_exited); + /* Make the handle invalid */ + handle = thread_handle(th->p_tid); + __pthread_lock(&handle->h_lock, NULL); + h_bottom_save = handle->h_bottom; + handle->h_descr = NULL; + handle->h_bottom = (char *)(-1L); + __pthread_unlock(&handle->h_lock); +#ifdef FREE_THREAD_SELF + FREE_THREAD_SELF(th, th->p_nr); +#endif + /* One fewer threads in __pthread_handles */ + __pthread_handles_num--; + + /* Destroy read lock list, and list of free read lock structures. + If the former is not empty, it means the thread exited while + holding read locks! */ + + for (iter = th->p_readlock_list; iter != NULL; iter = next) + { + next = iter->pr_next; + free(iter); + } + + for (iter = th->p_readlock_free; iter != NULL; iter = next) + { + next = iter->pr_next; + free(iter); + } + + /* If initial thread, nothing to free */ + if (th == &__pthread_initial_thread) return; +#ifdef __ARCH_HAS_MMU__ + if (!th->p_userstack) + { + /* Free the stack and thread descriptor area */ + if (th->p_guardsize != 0) + munmap(th->p_guardaddr, th->p_guardsize); + munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE); + } +#else + /* For non-MMU systems we always malloc the stack, so free it here. -StS */ + if (!th->p_userstack) { + free(h_bottom_save); + } +#endif /* __ARCH_HAS_MMU__ */ +} + +/* Handle threads that have exited */ + +static void pthread_exited(pid_t pid) +{ + pthread_descr th; + int detached; + /* Find thread with that pid */ + for (th = __pthread_main_thread->p_nextlive; + th != __pthread_main_thread; + th = th->p_nextlive) { + if (th->p_pid == pid) { + /* Remove thread from list of active threads */ + th->p_nextlive->p_prevlive = th->p_prevlive; + th->p_prevlive->p_nextlive = th->p_nextlive; + /* Mark thread as exited, and if detached, free its resources */ + __pthread_lock(th->p_lock, NULL); + th->p_exited = 1; + /* If we have to signal this event do it now. */ + if (th->p_report_events) + { + /* See whether TD_REAP is in any of the mask. */ + int idx = __td_eventword (TD_REAP); + uint32_t mask = __td_eventmask (TD_REAP); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | th->p_eventbuf.eventmask.event_bits[idx])) != 0) + { + /* Yep, we have to signal the reapage. */ + th->p_eventbuf.eventnum = TD_REAP; + th->p_eventbuf.eventdata = th; + __pthread_last_event = th; + + /* Now call the function to signal the event. */ + __linuxthreads_reap_event(); + } + } + detached = th->p_detached; + __pthread_unlock(th->p_lock); + if (detached) + pthread_free(th); + break; + } + } + /* If all threads have exited and the main thread is pending on a + pthread_exit, wake up the main thread and terminate ourselves. */ + if (main_thread_exiting && + __pthread_main_thread->p_nextlive == __pthread_main_thread) { + restart(__pthread_main_thread); + /* Same logic as REQ_MAIN_THREAD_EXIT. */ + } +} + +static void pthread_reap_children(void) +{ + pid_t pid; + int status; + PDEBUG("\n"); + + while ((pid = __libc_waitpid(-1, &status, WNOHANG | __WCLONE)) > 0) { + pthread_exited(pid); + if (WIFSIGNALED(status)) { + /* If a thread died due to a signal, send the same signal to + all other threads, including the main thread. */ + pthread_kill_all_threads(WTERMSIG(status), 1); + _exit(0); + } + } +} + +/* Try to free the resources of a thread when requested by pthread_join + or pthread_detach on a terminated thread. */ + +static void pthread_handle_free(pthread_t th_id) +{ + pthread_handle handle = thread_handle(th_id); + pthread_descr th; + + __pthread_lock(&handle->h_lock, NULL); + if (invalid_handle(handle, th_id)) { + /* pthread_reap_children has deallocated the thread already, + nothing needs to be done */ + __pthread_unlock(&handle->h_lock); + return; + } + th = handle->h_descr; + if (th->p_exited) { + __pthread_unlock(&handle->h_lock); + pthread_free(th); + } else { + /* The Unix process of the thread is still running. + Mark the thread as detached so that the thread manager will + deallocate its resources when the Unix process exits. */ + th->p_detached = 1; + __pthread_unlock(&handle->h_lock); + } +} + +/* Send a signal to all running threads */ + +static void pthread_kill_all_threads(int sig, int main_thread_also) +{ + pthread_descr th; + for (th = __pthread_main_thread->p_nextlive; + th != __pthread_main_thread; + th = th->p_nextlive) { + kill(th->p_pid, sig); + } + if (main_thread_also) { + kill(__pthread_main_thread->p_pid, sig); + } +} + +/* Process-wide exit() */ + +static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode) +{ + pthread_descr th; + __pthread_exit_requested = 1; + __pthread_exit_code = exitcode; + /* Send the CANCEL signal to all running threads, including the main + thread, but excluding the thread from which the exit request originated + (that thread must complete the exit, e.g. calling atexit functions + and flushing stdio buffers). */ + for (th = issuing_thread->p_nextlive; + th != issuing_thread; + th = th->p_nextlive) { + kill(th->p_pid, __pthread_sig_cancel); + } + /* Now, wait for all these threads, so that they don't become zombies + and their times are properly added to the thread manager's times. */ + for (th = issuing_thread->p_nextlive; + th != issuing_thread; + th = th->p_nextlive) { + waitpid(th->p_pid, NULL, __WCLONE); + } + restart(issuing_thread); + _exit(0); +} + +/* Handler for __pthread_sig_cancel in thread manager thread */ + +void __pthread_manager_sighandler(int sig) +{ + int kick_manager = terminated_children == 0 && main_thread_exiting; + terminated_children = 1; + + /* If the main thread is terminating, kick the thread manager loop + each time some threads terminate. This eliminates a two second + shutdown delay caused by the thread manager sleeping in the + call to __poll(). Instead, the thread manager is kicked into + action, reaps the outstanding threads and resumes the main thread + so that it can complete the shutdown. */ + + if (kick_manager) { + struct pthread_request request; + request.req_thread = 0; + request.req_kind = REQ_KICK; + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); + } +} + +/* Adjust priority of thread manager so that it always run at a priority + higher than all threads */ + +void __pthread_manager_adjust_prio(int thread_prio) +{ + struct sched_param param; + + if (thread_prio <= __pthread_manager_thread.p_priority) return; + param.sched_priority = + thread_prio < sched_get_priority_max(SCHED_FIFO) + ? thread_prio + 1 : thread_prio; + sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, ¶m); + __pthread_manager_thread.p_priority = thread_prio; +} diff --git a/libpthread/linuxthreads.old/mutex.c b/libpthread/linuxthreads.old/mutex.c new file mode 100644 index 000000000..7cc344fac --- /dev/null +++ b/libpthread/linuxthreads.old/mutex.c @@ -0,0 +1,356 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Mutexes */ + +#include +#include +#include +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "queue.h" +#include "restart.h" + +int __pthread_mutex_init(pthread_mutex_t * mutex, + const pthread_mutexattr_t * mutex_attr) +{ + __pthread_init_lock(&mutex->__m_lock); + mutex->__m_kind = + mutex_attr == NULL ? PTHREAD_MUTEX_TIMED_NP : mutex_attr->__mutexkind; + mutex->__m_count = 0; + mutex->__m_owner = NULL; + return 0; +} +strong_alias (__pthread_mutex_init, pthread_mutex_init) + +int __pthread_mutex_destroy(pthread_mutex_t * mutex) +{ + switch (mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + case PTHREAD_MUTEX_RECURSIVE_NP: + if ((mutex->__m_lock.__status & 1) != 0) + return EBUSY; + return 0; + case PTHREAD_MUTEX_ERRORCHECK_NP: + case PTHREAD_MUTEX_TIMED_NP: + if (mutex->__m_lock.__status != 0) + return EBUSY; + return 0; + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy) + +int __pthread_mutex_trylock(pthread_mutex_t * mutex) +{ + pthread_descr self; + int retcode; + + switch(mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + retcode = __pthread_trylock(&mutex->__m_lock); + return retcode; + case PTHREAD_MUTEX_RECURSIVE_NP: + self = thread_self(); + if (mutex->__m_owner == self) { + mutex->__m_count++; + return 0; + } + retcode = __pthread_trylock(&mutex->__m_lock); + if (retcode == 0) { + mutex->__m_owner = self; + mutex->__m_count = 0; + } + return retcode; + case PTHREAD_MUTEX_ERRORCHECK_NP: + retcode = __pthread_alt_trylock(&mutex->__m_lock); + if (retcode == 0) { + mutex->__m_owner = thread_self(); + } + return retcode; + case PTHREAD_MUTEX_TIMED_NP: + retcode = __pthread_alt_trylock(&mutex->__m_lock); + return retcode; + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock) + +int __pthread_mutex_lock(pthread_mutex_t * mutex) +{ + pthread_descr self; + + switch(mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + __pthread_lock(&mutex->__m_lock, NULL); + return 0; + case PTHREAD_MUTEX_RECURSIVE_NP: + self = thread_self(); + if (mutex->__m_owner == self) { + mutex->__m_count++; + return 0; + } + __pthread_lock(&mutex->__m_lock, self); + mutex->__m_owner = self; + mutex->__m_count = 0; + return 0; + case PTHREAD_MUTEX_ERRORCHECK_NP: + self = thread_self(); + if (mutex->__m_owner == self) return EDEADLK; + __pthread_alt_lock(&mutex->__m_lock, self); + mutex->__m_owner = self; + return 0; + case PTHREAD_MUTEX_TIMED_NP: + __pthread_alt_lock(&mutex->__m_lock, NULL); + return 0; + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_lock, pthread_mutex_lock) + +int __pthread_mutex_timedlock (pthread_mutex_t *mutex, + const struct timespec *abstime) +{ + pthread_descr self; + int res; + + if (__builtin_expect (abstime->tv_nsec, 0) < 0 + || __builtin_expect (abstime->tv_nsec, 0) >= 1000000000) + return EINVAL; + + switch(mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + __pthread_lock(&mutex->__m_lock, NULL); + return 0; + case PTHREAD_MUTEX_RECURSIVE_NP: + self = thread_self(); + if (mutex->__m_owner == self) { + mutex->__m_count++; + return 0; + } + __pthread_lock(&mutex->__m_lock, self); + mutex->__m_owner = self; + mutex->__m_count = 0; + return 0; + case PTHREAD_MUTEX_ERRORCHECK_NP: + self = thread_self(); + if (mutex->__m_owner == self) return EDEADLK; + res = __pthread_alt_timedlock(&mutex->__m_lock, self, abstime); + if (res != 0) + { + mutex->__m_owner = self; + return 0; + } + return ETIMEDOUT; + case PTHREAD_MUTEX_TIMED_NP: + /* Only this type supports timed out lock. */ + return (__pthread_alt_timedlock(&mutex->__m_lock, NULL, abstime) + ? 0 : ETIMEDOUT); + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_timedlock, pthread_mutex_timedlock) + +int __pthread_mutex_unlock(pthread_mutex_t * mutex) +{ + switch (mutex->__m_kind) { + case PTHREAD_MUTEX_ADAPTIVE_NP: + __pthread_unlock(&mutex->__m_lock); + return 0; + case PTHREAD_MUTEX_RECURSIVE_NP: + if (mutex->__m_owner != thread_self()) + return EPERM; + if (mutex->__m_count > 0) { + mutex->__m_count--; + return 0; + } + mutex->__m_owner = NULL; + __pthread_unlock(&mutex->__m_lock); + return 0; + case PTHREAD_MUTEX_ERRORCHECK_NP: + if (mutex->__m_owner != thread_self() || mutex->__m_lock.__status == 0) + return EPERM; + mutex->__m_owner = NULL; + __pthread_alt_unlock(&mutex->__m_lock); + return 0; + case PTHREAD_MUTEX_TIMED_NP: + __pthread_alt_unlock(&mutex->__m_lock); + return 0; + default: + return EINVAL; + } +} +strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock) + +int __pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + attr->__mutexkind = PTHREAD_MUTEX_TIMED_NP; + return 0; +} +strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init) + +int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + return 0; +} +strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy) + +int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind) +{ + if (kind != PTHREAD_MUTEX_ADAPTIVE_NP + && kind != PTHREAD_MUTEX_RECURSIVE_NP + && kind != PTHREAD_MUTEX_ERRORCHECK_NP + && kind != PTHREAD_MUTEX_TIMED_NP) + return EINVAL; + attr->__mutexkind = kind; + return 0; +} +weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype) +strong_alias ( __pthread_mutexattr_settype, __pthread_mutexattr_setkind_np) +weak_alias (__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np) + +int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind) +{ + *kind = attr->__mutexkind; + return 0; +} +weak_alias (__pthread_mutexattr_gettype, pthread_mutexattr_gettype) +strong_alias (__pthread_mutexattr_gettype, __pthread_mutexattr_getkind_np) +weak_alias (__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np) + +int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, + int *pshared) +{ + *pshared = PTHREAD_PROCESS_PRIVATE; + return 0; +} +weak_alias (__pthread_mutexattr_getpshared, pthread_mutexattr_getpshared) + +int __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + /* For now it is not possible to shared a conditional variable. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; + + return 0; +} +weak_alias (__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared) + +/* Once-only execution */ + +static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t once_finished = PTHREAD_COND_INITIALIZER; +static int fork_generation = 0; /* Child process increments this after fork. */ + +enum { NEVER = 0, IN_PROGRESS = 1, DONE = 2 }; + +/* If a thread is canceled while calling the init_routine out of + pthread once, this handler will reset the once_control variable + to the NEVER state. */ + +static void pthread_once_cancelhandler(void *arg) +{ + pthread_once_t *once_control = arg; + + pthread_mutex_lock(&once_masterlock); + *once_control = NEVER; + pthread_mutex_unlock(&once_masterlock); + pthread_cond_broadcast(&once_finished); +} + +int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void)) +{ + /* flag for doing the condition broadcast outside of mutex */ + int state_changed; + + /* Test without locking first for speed */ + if (*once_control == DONE) { + READ_MEMORY_BARRIER(); + return 0; + } + /* Lock and test again */ + + state_changed = 0; + + pthread_mutex_lock(&once_masterlock); + + /* If this object was left in an IN_PROGRESS state in a parent + process (indicated by stale generation field), reset it to NEVER. */ + if ((*once_control & 3) == IN_PROGRESS && (*once_control & ~3) != fork_generation) + *once_control = NEVER; + + /* If init_routine is being called from another routine, wait until + it completes. */ + while ((*once_control & 3) == IN_PROGRESS) { + pthread_cond_wait(&once_finished, &once_masterlock); + } + /* Here *once_control is stable and either NEVER or DONE. */ + if (*once_control == NEVER) { + *once_control = IN_PROGRESS | fork_generation; + pthread_mutex_unlock(&once_masterlock); + pthread_cleanup_push(pthread_once_cancelhandler, once_control); + init_routine(); + pthread_cleanup_pop(0); + pthread_mutex_lock(&once_masterlock); + WRITE_MEMORY_BARRIER(); + *once_control = DONE; + state_changed = 1; + } + pthread_mutex_unlock(&once_masterlock); + + if (state_changed) + pthread_cond_broadcast(&once_finished); + + return 0; +} +strong_alias (__pthread_once, pthread_once) + +/* + * Handle the state of the pthread_once mechanism across forks. The + * once_masterlock is acquired in the parent process prior to a fork to ensure + * that no thread is in the critical region protected by the lock. After the + * fork, the lock is released. In the child, the lock and the condition + * variable are simply reset. The child also increments its generation + * counter which lets pthread_once calls detect stale IN_PROGRESS states + * and reset them back to NEVER. + */ + +void __pthread_once_fork_prepare(void) +{ + pthread_mutex_lock(&once_masterlock); +} + +void __pthread_once_fork_parent(void) +{ + pthread_mutex_unlock(&once_masterlock); +} + +void __pthread_once_fork_child(void) +{ + pthread_mutex_init(&once_masterlock, NULL); + pthread_cond_init(&once_finished, NULL); + if (fork_generation <= INT_MAX - 4) + fork_generation += 4; /* leave least significant two bits zero */ + else + fork_generation = 0; +} diff --git a/libpthread/linuxthreads.old/oldsemaphore.c b/libpthread/linuxthreads.old/oldsemaphore.c new file mode 100644 index 000000000..3a3b3d186 --- /dev/null +++ b/libpthread/linuxthreads.old/oldsemaphore.c @@ -0,0 +1,235 @@ +/* + * This file contains the old semaphore code that we need to + * preserve for glibc-2.0 backwards compatibility. Port to glibc 2.1 + * done by Cristian Gafton. + */ + +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Semaphores a la POSIX 1003.1b */ + +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "queue.h" + +typedef struct { + long int sem_status; + int sem_spinlock; +} old_sem_t; + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX ((int) ((~0u) >> 1)) + +static inline int sem_compare_and_swap(old_sem_t *sem, long oldval, long newval) +{ + return compare_and_swap(&sem->sem_status, oldval, newval, &sem->sem_spinlock); +} + +/* The state of a semaphore is represented by a long int encoding + either the semaphore count if >= 0 and no thread is waiting on it, + or the head of the list of threads waiting for the semaphore. + To distinguish the two cases, we encode the semaphore count N + as 2N+1, so that it has the lowest bit set. + + A sequence of sem_wait operations on a semaphore initialized to N + result in the following successive states: + 2N+1, 2N-1, ..., 3, 1, &first_waiting_thread, &second_waiting_thread, ... +*/ + +static void sem_restart_list(pthread_descr waiting); + +int __old_sem_init(old_sem_t *sem, int pshared, unsigned int value) +{ + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return -1; + } + if (pshared) { + errno = ENOSYS; + return -1; + } + sem->sem_spinlock = 0; + sem->sem_status = ((long)value << 1) + 1; + return 0; +} + +/* Function called by pthread_cancel to remove the thread from + waiting inside __old_sem_wait. Here we simply unconditionally + indicate that the thread is to be woken, by returning 1. */ + +static int old_sem_extricate_func(void *obj, pthread_descr th) +{ + return 1; +} + +int __old_sem_wait(old_sem_t * sem) +{ + long oldstatus, newstatus; + volatile pthread_descr self = thread_self(); + pthread_descr * th; + pthread_extricate_if extr; + + /* Set up extrication interface */ + extr.pu_object = 0; + extr.pu_extricate_func = old_sem_extricate_func; + + while (1) { + /* Register extrication interface */ + __pthread_set_own_extricate_if(self, &extr); + do { + oldstatus = sem->sem_status; + if ((oldstatus & 1) && (oldstatus != 1)) + newstatus = oldstatus - 2; + else { + newstatus = (long) self; + self->p_nextwaiting = (pthread_descr) oldstatus; + } + } + while (! sem_compare_and_swap(sem, oldstatus, newstatus)); + if (newstatus & 1) { + /* We got the semaphore. */ + __pthread_set_own_extricate_if(self, 0); + return 0; + } + /* Wait for sem_post or cancellation */ + suspend(self); + __pthread_set_own_extricate_if(self, 0); + + /* This is a cancellation point */ + if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { + /* Remove ourselves from the waiting list if we're still on it */ + /* First check if we're at the head of the list. */ + do { + oldstatus = sem->sem_status; + if (oldstatus != (long) self) break; + newstatus = (long) self->p_nextwaiting; + } + while (! sem_compare_and_swap(sem, oldstatus, newstatus)); + /* Now, check if we're somewhere in the list. + There's a race condition with sem_post here, but it does not matter: + the net result is that at the time pthread_exit is called, + self is no longer reachable from sem->sem_status. */ + if (oldstatus != (long) self && (oldstatus & 1) == 0) { + for (th = &(((pthread_descr) oldstatus)->p_nextwaiting); + *th != NULL && *th != (pthread_descr) 1; + th = &((*th)->p_nextwaiting)) { + if (*th == self) { + *th = self->p_nextwaiting; + break; + } + } + } + pthread_exit(PTHREAD_CANCELED); + } + } +} + +int __old_sem_trywait(old_sem_t * sem) +{ + long oldstatus, newstatus; + + do { + oldstatus = sem->sem_status; + if ((oldstatus & 1) == 0 || (oldstatus == 1)) { + errno = EAGAIN; + return -1; + } + newstatus = oldstatus - 2; + } + while (! sem_compare_and_swap(sem, oldstatus, newstatus)); + return 0; +} + +int __old_sem_post(old_sem_t * sem) +{ + long oldstatus, newstatus; + + do { + oldstatus = sem->sem_status; + if ((oldstatus & 1) == 0) + newstatus = 3; + else { + if (oldstatus >= SEM_VALUE_MAX) { + /* Overflow */ + errno = ERANGE; + return -1; + } + newstatus = oldstatus + 2; + } + } + while (! sem_compare_and_swap(sem, oldstatus, newstatus)); + if ((oldstatus & 1) == 0) + sem_restart_list((pthread_descr) oldstatus); + return 0; +} + +int __old_sem_getvalue(old_sem_t * sem, int * sval) +{ + long status = sem->sem_status; + if (status & 1) + *sval = (int)((unsigned long) status >> 1); + else + *sval = 0; + return 0; +} + +int __old_sem_destroy(old_sem_t * sem) +{ + if ((sem->sem_status & 1) == 0) { + errno = EBUSY; + return -1; + } + return 0; +} + +/* Auxiliary function for restarting all threads on a waiting list, + in priority order. */ + +static void sem_restart_list(pthread_descr waiting) +{ + pthread_descr th, towake, *p; + + /* Sort list of waiting threads by decreasing priority (insertion sort) */ + towake = NULL; + while (waiting != (pthread_descr) 1) { + th = waiting; + waiting = waiting->p_nextwaiting; + p = &towake; + while (*p != NULL && th->p_priority < (*p)->p_priority) + p = &((*p)->p_nextwaiting); + th->p_nextwaiting = *p; + *p = th; + } + /* Wake up threads in priority order */ + while (towake != NULL) { + th = towake; + towake = towake->p_nextwaiting; + th->p_nextwaiting = NULL; + restart(th); + } +} + +#if defined __PIC__ && defined DO_VERSIONING +symbol_version (__old_sem_init, sem_init, GLIBC_2.0); +symbol_version (__old_sem_wait, sem_wait, GLIBC_2.0); +symbol_version (__old_sem_trywait, sem_trywait, GLIBC_2.0); +symbol_version (__old_sem_post, sem_post, GLIBC_2.0); +symbol_version (__old_sem_getvalue, sem_getvalue, GLIBC_2.0); +symbol_version (__old_sem_destroy, sem_destroy, GLIBC_2.0); +#endif + diff --git a/libpthread/linuxthreads.old/pt-machine.c b/libpthread/linuxthreads.old/pt-machine.c new file mode 100644 index 000000000..438008d5d --- /dev/null +++ b/libpthread/linuxthreads.old/pt-machine.c @@ -0,0 +1,22 @@ +/* "Instantiation of machine-dependent pthreads inline functions. + Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define PT_EI + +#include diff --git a/libpthread/linuxthreads.old/ptfork.c b/libpthread/linuxthreads.old/ptfork.c new file mode 100644 index 000000000..eb544f34b --- /dev/null +++ b/libpthread/linuxthreads.old/ptfork.c @@ -0,0 +1,126 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* mods for uClibc: removed strong alias and defined funcs properly */ + +/* The "atfork" stuff */ + +#include + +#ifdef __ARCH_HAS_MMU__ + +#include +#include +#include +#include "pthread.h" +#include "internals.h" + +struct handler_list { + void (*handler)(void); + struct handler_list * next; +}; + +static pthread_mutex_t pthread_atfork_lock = PTHREAD_MUTEX_INITIALIZER; +static struct handler_list * pthread_atfork_prepare = NULL; +static struct handler_list * pthread_atfork_parent = NULL; +static struct handler_list * pthread_atfork_child = NULL; + +static void pthread_insert_list(struct handler_list ** list, + void (*handler)(void), + struct handler_list * newlist, + int at_end) +{ + if (handler == NULL) return; + if (at_end) { + while(*list != NULL) list = &((*list)->next); + } + newlist->handler = handler; + newlist->next = *list; + *list = newlist; +} + +struct handler_list_block { + struct handler_list prepare, parent, child; +}; + +int pthread_atfork(void (*prepare)(void), + void (*parent)(void), + void (*child)(void)) +{ + struct handler_list_block * block = + (struct handler_list_block *) malloc(sizeof(struct handler_list_block)); + if (block == NULL) return ENOMEM; + pthread_mutex_lock(&pthread_atfork_lock); + /* "prepare" handlers are called in LIFO */ + pthread_insert_list(&pthread_atfork_prepare, prepare, &block->prepare, 0); + /* "parent" handlers are called in FIFO */ + pthread_insert_list(&pthread_atfork_parent, parent, &block->parent, 1); + /* "child" handlers are called in FIFO */ + pthread_insert_list(&pthread_atfork_child, child, &block->child, 1); + pthread_mutex_unlock(&pthread_atfork_lock); + return 0; +} +//strong_alias (__pthread_atfork, pthread_atfork) + +static inline void pthread_call_handlers(struct handler_list * list) +{ + for (/*nothing*/; list != NULL; list = list->next) (list->handler)(); +} + +extern int __libc_fork(void); + +pid_t __fork(void) +{ + pid_t pid; + struct handler_list * prepare, * child, * parent; + + pthread_mutex_lock(&pthread_atfork_lock); + prepare = pthread_atfork_prepare; + child = pthread_atfork_child; + parent = pthread_atfork_parent; + pthread_mutex_unlock(&pthread_atfork_lock); + pthread_call_handlers(prepare); + pid = __libc_fork(); + if (pid == 0) { + __pthread_reset_main_thread(); + __fresetlockfiles(); + pthread_call_handlers(child); + } else { + pthread_call_handlers(parent); + } + return pid; +} +weak_alias (__fork, fork); + +pid_t __vfork(void) +{ + return __fork(); +} +weak_alias (__vfork, vfork); + +#else + +/* We can't support pthread_atfork without MMU, since we don't have + fork(), and we can't offer the correct semantics for vfork(). */ +int pthread_atfork(void (*prepare)(void), + void (*parent)(void), + void (*child)(void)) +{ + /* ENOMEM is probably pushing it a little bit. + Take it as `no *virtual* memory' :-) */ + errno = ENOMEM; + return -1; +} + +#endif diff --git a/libpthread/linuxthreads.old/pthread.c b/libpthread/linuxthreads.old/pthread.c new file mode 100644 index 000000000..fed3d8c72 --- /dev/null +++ b/libpthread/linuxthreads.old/pthread.c @@ -0,0 +1,1044 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Thread creation, initialization, and basic low-level routines */ + +#define __FORCE_GLIBC +#include +#define __USE_GNU +#include +#include /* for h_errno */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "debug.h" /* added to linuxthreads -StS */ + + +/* Mods for uClibc: Some includes */ +#include +#include +#include + +/* mods for uClibc: getpwd and getpagesize are the syscalls */ +#define __getpid getpid +#define __getpagesize getpagesize +/* mods for uClibc: __libc_sigaction is not in any standard headers */ +extern int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact); + + +/* These variables are used by the setup code. */ +extern int _errno; +extern int _h_errno; + + +/* Descriptor of the initial thread */ + +struct _pthread_descr_struct __pthread_initial_thread = { + &__pthread_initial_thread, /* pthread_descr p_nextlive */ + &__pthread_initial_thread, /* pthread_descr p_prevlive */ + NULL, /* pthread_descr p_nextwaiting */ + NULL, /* pthread_descr p_nextlock */ + PTHREAD_THREADS_MAX, /* pthread_t p_tid */ + 0, /* int p_pid */ + 0, /* int p_priority */ + &__pthread_handles[0].h_lock, /* struct _pthread_fastlock * p_lock */ + 0, /* int p_signal */ + NULL, /* sigjmp_buf * p_signal_buf */ + NULL, /* sigjmp_buf * p_cancel_buf */ + 0, /* char p_terminated */ + 0, /* char p_detached */ + 0, /* char p_exited */ + NULL, /* void * p_retval */ + 0, /* int p_retval */ + NULL, /* pthread_descr p_joining */ + NULL, /* struct _pthread_cleanup_buffer * p_cleanup */ + 0, /* char p_cancelstate */ + 0, /* char p_canceltype */ + 0, /* char p_canceled */ + &_errno, /* int *p_errnop */ + 0, /* int p_errno */ + &_h_errno, /* int *p_h_errnop */ + 0, /* int p_h_errno */ + NULL, /* char * p_in_sighandler */ + 0, /* char p_sigwaiting */ + PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */ + {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */ + {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */ + 0, /* int p_userstack */ + NULL, /* void * p_guardaddr */ + 0, /* size_t p_guardsize */ + &__pthread_initial_thread, /* pthread_descr p_self */ + 0, /* Always index 0 */ + 0, /* int p_report_events */ + {{{0, }}, 0, NULL}, /* td_eventbuf_t p_eventbuf */ + __ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */ + 0, /* char p_woken_by_cancel */ + 0, /* char p_condvar_avail */ + 0, /* char p_sem_avail */ + NULL, /* struct pthread_extricate_if *p_extricate */ + NULL, /* pthread_readlock_info *p_readlock_list; */ + NULL, /* pthread_readlock_info *p_readlock_free; */ + 0 /* int p_untracked_readlock_count; */ +#ifdef __UCLIBC_HAS_XLOCALE__ + , + &__global_locale_data, /* __locale_t locale; */ +#endif /* __UCLIBC_HAS_XLOCALE__ */ +}; + +/* Descriptor of the manager thread; none of this is used but the error + variables, the p_pid and p_priority fields, + and the address for identification. */ +#define manager_thread (&__pthread_manager_thread) +struct _pthread_descr_struct __pthread_manager_thread = { + NULL, /* pthread_descr p_nextlive */ + NULL, /* pthread_descr p_prevlive */ + NULL, /* pthread_descr p_nextwaiting */ + NULL, /* pthread_descr p_nextlock */ + 0, /* int p_tid */ + 0, /* int p_pid */ + 0, /* int p_priority */ + &__pthread_handles[1].h_lock, /* struct _pthread_fastlock * p_lock */ + 0, /* int p_signal */ + NULL, /* sigjmp_buf * p_signal_buf */ + NULL, /* sigjmp_buf * p_cancel_buf */ + 0, /* char p_terminated */ + 0, /* char p_detached */ + 0, /* char p_exited */ + NULL, /* void * p_retval */ + 0, /* int p_retval */ + NULL, /* pthread_descr p_joining */ + NULL, /* struct _pthread_cleanup_buffer * p_cleanup */ + 0, /* char p_cancelstate */ + 0, /* char p_canceltype */ + 0, /* char p_canceled */ + &__pthread_manager_thread.p_errno, /* int *p_errnop */ + 0, /* int p_errno */ + NULL, /* int *p_h_errnop */ + 0, /* int p_h_errno */ + NULL, /* char * p_in_sighandler */ + 0, /* char p_sigwaiting */ + PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */ + {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */ + {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */ + 0, /* int p_userstack */ + NULL, /* void * p_guardaddr */ + 0, /* size_t p_guardsize */ + &__pthread_manager_thread, /* pthread_descr p_self */ + 1, /* Always index 1 */ + 0, /* int p_report_events */ + {{{0, }}, 0, NULL}, /* td_eventbuf_t p_eventbuf */ + __ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */ + 0, /* char p_woken_by_cancel */ + 0, /* char p_condvar_avail */ + 0, /* char p_sem_avail */ + NULL, /* struct pthread_extricate_if *p_extricate */ + NULL, /* pthread_readlock_info *p_readlock_list; */ + NULL, /* pthread_readlock_info *p_readlock_free; */ + 0 /* int p_untracked_readlock_count; */ +#ifdef __UCLIBC_HAS_XLOCALE__ + , + &__global_locale_data, /* __locale_t locale; */ +#endif /* __UCLIBC_HAS_XLOCALE__ */ +}; + +/* Pointer to the main thread (the father of the thread manager thread) */ +/* Originally, this is the initial thread, but this changes after fork() */ + +pthread_descr __pthread_main_thread = &__pthread_initial_thread; + +/* Limit between the stack of the initial thread (above) and the + stacks of other threads (below). Aligned on a STACK_SIZE boundary. */ + +char *__pthread_initial_thread_bos = NULL; + +/* For non-MMU systems also remember to stack top of the initial thread. + * This is adapted when other stacks are malloc'ed since we don't know + * the bounds a-priori. -StS */ + +#ifndef __ARCH_HAS_MMU__ +char *__pthread_initial_thread_tos = NULL; +#endif /* __ARCH_HAS_MMU__ */ + +/* File descriptor for sending requests to the thread manager. */ +/* Initially -1, meaning that the thread manager is not running. */ + +int __pthread_manager_request = -1; + +/* Other end of the pipe for sending requests to the thread manager. */ + +int __pthread_manager_reader; + +/* Limits of the thread manager stack */ + +char *__pthread_manager_thread_bos = NULL; +char *__pthread_manager_thread_tos = NULL; + +/* For process-wide exit() */ + +int __pthread_exit_requested = 0; +int __pthread_exit_code = 0; + +/* Communicate relevant LinuxThreads constants to gdb */ + +const int __pthread_threads_max = PTHREAD_THREADS_MAX; +const int __pthread_sizeof_handle = sizeof(struct pthread_handle_struct); +const int __pthread_offsetof_descr = offsetof(struct pthread_handle_struct, h_descr); +const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct, + p_pid); +const int __linuxthreads_pthread_sizeof_descr + = sizeof(struct _pthread_descr_struct); + +const int __linuxthreads_initial_report_events; + +const char __linuxthreads_version[] = VERSION; + +/* Forward declarations */ +static void pthread_onexit_process(int retcode, void *arg); +static void pthread_handle_sigcancel(int sig); +static void pthread_handle_sigrestart(int sig); +static void pthread_handle_sigdebug(int sig); +int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime); + +/* Signal numbers used for the communication. + In these variables we keep track of the used variables. If the + platform does not support any real-time signals we will define the + values to some unreasonable value which will signal failing of all + the functions below. */ +#ifndef __NR_rt_sigaction +static int current_rtmin = -1; +static int current_rtmax = -1; +int __pthread_sig_restart = SIGUSR1; +int __pthread_sig_cancel = SIGUSR2; +int __pthread_sig_debug; +#else + +#if __SIGRTMAX - __SIGRTMIN >= 3 +static int current_rtmin = __SIGRTMIN + 3; +static int current_rtmax = __SIGRTMAX; +int __pthread_sig_restart = __SIGRTMIN; +int __pthread_sig_cancel = __SIGRTMIN + 1; +int __pthread_sig_debug = __SIGRTMIN + 2; +void (*__pthread_restart)(pthread_descr) = __pthread_restart_new; +void (*__pthread_suspend)(pthread_descr) = __pthread_wait_for_restart_signal; +int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_new; +#else +static int current_rtmin = __SIGRTMIN; +static int current_rtmax = __SIGRTMAX; +int __pthread_sig_restart = SIGUSR1; +int __pthread_sig_cancel = SIGUSR2; +int __pthread_sig_debug; +void (*__pthread_restart)(pthread_descr) = __pthread_restart_old; +void (*__pthread_suspend)(pthread_descr) = __pthread_suspend_old; +int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_old; + +#endif + +/* Return number of available real-time signal with highest priority. */ +int __libc_current_sigrtmin (void) +{ + return current_rtmin; +} + +/* Return number of available real-time signal with lowest priority. */ +int __libc_current_sigrtmax (void) +{ + return current_rtmax; +} + +/* Allocate real-time signal with highest/lowest available + priority. Please note that we don't use a lock since we assume + this function to be called at program start. */ +int __libc_allocate_rtsig (int high) +{ + if (current_rtmin == -1 || current_rtmin > current_rtmax) + /* We don't have anymore signal available. */ + return -1; + return high ? current_rtmin++ : current_rtmax--; +} +#endif + +/* Initialize the pthread library. + Initialization is split in two functions: + - a constructor function that blocks the __pthread_sig_restart signal + (must do this very early, since the program could capture the signal + mask with e.g. sigsetjmp before creating the first thread); + - a regular function called from pthread_create when needed. */ + +static void pthread_initialize(void) __attribute__((constructor)); + + /* Do some minimal initialization which has to be done during the + startup of the C library. */ +void __pthread_initialize_minimal(void) +{ + /* If we have special thread_self processing, initialize + * that for the main thread now. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(&__pthread_initial_thread, 0); +#endif +} + + +static void pthread_initialize(void) +{ + struct sigaction sa; + sigset_t mask; + struct rlimit limit; + int max_stack; + + /* If already done (e.g. by a constructor called earlier!), bail out */ + if (__pthread_initial_thread_bos != NULL) return; +#ifdef TEST_FOR_COMPARE_AND_SWAP + /* Test if compare-and-swap is available */ + __pthread_has_cas = compare_and_swap_is_available(); +#endif + /* For the initial stack, reserve at least STACK_SIZE bytes of stack + below the current stack address, and align that on a + STACK_SIZE boundary. */ + __pthread_initial_thread_bos = + (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1)); + /* Update the descriptor for the initial thread. */ + __pthread_initial_thread.p_pid = __getpid(); + /* If we have special thread_self processing, initialize that for the + main thread now. */ +#ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(&__pthread_initial_thread, 0); +#endif + /* The errno/h_errno variable of the main thread are the global ones. */ + __pthread_initial_thread.p_errnop = &_errno; + __pthread_initial_thread.p_h_errnop = &_h_errno; + +#ifdef __UCLIBC_HAS_XLOCALE__ + /* The locale of the main thread is the current locale in use. */ + __pthread_initial_thread.locale = __curlocale_var; +#endif /* __UCLIBC_HAS_XLOCALE__ */ + + { /* uClibc-specific stdio initialization for threads. */ + FILE *fp; + + _stdio_user_locking = 0; /* 2 if threading not initialized */ + for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) { + if (fp->__user_locking != 1) { + fp->__user_locking = 0; + } + } + } + + /* Play with the stack size limit to make sure that no stack ever grows + beyond STACK_SIZE minus two pages (one page for the thread descriptor + immediately beyond, and one page to act as a guard page). */ + +#ifdef __ARCH_HAS_MMU__ + /* We cannot allocate a huge chunk of memory to mmap all thread stacks later + * on a non-MMU system. Thus, we don't need the rlimit either. -StS */ + getrlimit(RLIMIT_STACK, &limit); + max_stack = STACK_SIZE - 2 * __getpagesize(); + if (limit.rlim_cur > max_stack) { + limit.rlim_cur = max_stack; + setrlimit(RLIMIT_STACK, &limit); + } +#else + /* For non-MMU assume __pthread_initial_thread_tos at upper page boundary, and + * __pthread_initial_thread_bos at address 0. These bounds are refined as we + * malloc other stack frames such that they don't overlap. -StS + */ + __pthread_initial_thread_tos = + (char *)(((long)CURRENT_STACK_FRAME + __getpagesize()) & ~(__getpagesize() - 1)); + __pthread_initial_thread_bos = (char *) 1; /* set it non-zero so we know we have been here */ + PDEBUG("initial thread stack bounds: bos=%p, tos=%p\n", + __pthread_initial_thread_bos, __pthread_initial_thread_tos); +#endif /* __ARCH_HAS_MMU__ */ + + /* Setup signal handlers for the initial thread. + Since signal handlers are shared between threads, these settings + will be inherited by all other threads. */ + sa.sa_handler = pthread_handle_sigrestart; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + __libc_sigaction(__pthread_sig_restart, &sa, NULL); + sa.sa_handler = pthread_handle_sigcancel; + sigaddset(&sa.sa_mask, __pthread_sig_restart); + // sa.sa_flags = 0; + __libc_sigaction(__pthread_sig_cancel, &sa, NULL); + if (__pthread_sig_debug > 0) { + sa.sa_handler = pthread_handle_sigdebug; + sigemptyset(&sa.sa_mask); + // sa.sa_flags = 0; + __libc_sigaction(__pthread_sig_debug, &sa, NULL); + } + /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */ + sigemptyset(&mask); + sigaddset(&mask, __pthread_sig_restart); + sigprocmask(SIG_BLOCK, &mask, NULL); + /* And unblock __pthread_sig_cancel if it has been blocked. */ + sigdelset(&mask, __pthread_sig_restart); + sigaddset(&mask, __pthread_sig_cancel); + sigprocmask(SIG_UNBLOCK, &mask, NULL); + /* Register an exit function to kill all other threads. */ + /* Do it early so that user-registered atexit functions are called + before pthread_onexit_process. */ + on_exit(pthread_onexit_process, NULL); +} + +void __pthread_initialize(void) +{ + pthread_initialize(); +} + +int __pthread_initialize_manager(void) +{ + int manager_pipe[2]; + int pid; + int report_events; + struct pthread_request request; + + /* If basic initialization not done yet (e.g. we're called from a + constructor run before our constructor), do it now */ + if (__pthread_initial_thread_bos == NULL) pthread_initialize(); + /* Setup stack for thread manager */ + __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE); + if (__pthread_manager_thread_bos == NULL) return -1; + __pthread_manager_thread_tos = + __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE; + + /* On non-MMU systems we make sure that the initial thread bounds don't overlap + * with the manager stack frame */ + NOMMU_INITIAL_THREAD_BOUNDS(__pthread_manager_thread_tos,__pthread_manager_thread_bos); + PDEBUG("manager stack: size=%d, bos=%p, tos=%p\n", THREAD_MANAGER_STACK_SIZE, + __pthread_manager_thread_bos, __pthread_manager_thread_tos); +#if 0 + PDEBUG("initial stack: estimate bos=%p, tos=%p\n", + __pthread_initial_thread_bos, __pthread_initial_thread_tos); +#endif + + /* Setup pipe to communicate with thread manager */ + if (pipe(manager_pipe) == -1) { + free(__pthread_manager_thread_bos); + return -1; + } + /* Start the thread manager */ + pid = 0; +#ifdef USE_TLS + if (__linuxthreads_initial_report_events != 0) + THREAD_SETMEM (((pthread_descr) NULL), p_report_events, + __linuxthreads_initial_report_events); + report_events = THREAD_GETMEM (((pthread_descr) NULL), p_report_events); +#else + if (__linuxthreads_initial_report_events != 0) + __pthread_initial_thread.p_report_events + = __linuxthreads_initial_report_events; + report_events = __pthread_initial_thread.p_report_events; +#endif + if (__builtin_expect (report_events, 0)) + { + /* It's a bit more complicated. We have to report the creation of + the manager thread. */ + int idx = __td_eventword (TD_CREATE); + uint32_t mask = __td_eventmask (TD_CREATE); + + if ((mask & (__pthread_threads_events.event_bits[idx] + | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx])) + != 0) + { + + __pthread_lock(__pthread_manager_thread.p_lock, NULL); + + pid = clone(__pthread_manager_event, + (void **) __pthread_manager_thread_tos, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, + (void *)(long)manager_pipe[0]); + + if (pid != -1) + { + /* Now fill in the information about the new thread in + the newly created thread's data structure. We cannot let + the new thread do this since we don't know whether it was + already scheduled when we send the event. */ + __pthread_manager_thread.p_eventbuf.eventdata = + &__pthread_manager_thread; + __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE; + __pthread_last_event = &__pthread_manager_thread; + __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; + __pthread_manager_thread.p_pid = pid; + + /* Now call the function which signals the event. */ + __linuxthreads_create_event (); + } + /* Now restart the thread. */ + __pthread_unlock(__pthread_manager_thread.p_lock); + } + } + + if (pid == 0) { + pid = clone(__pthread_manager, (void **) __pthread_manager_thread_tos, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, + (void *)(long)manager_pipe[0]); + } + if (pid == -1) { + free(__pthread_manager_thread_bos); + __libc_close(manager_pipe[0]); + __libc_close(manager_pipe[1]); + return -1; + } + __pthread_manager_request = manager_pipe[1]; /* writing end */ + __pthread_manager_reader = manager_pipe[0]; /* reading end */ + __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; + __pthread_manager_thread.p_pid = pid; + + /* Make gdb aware of new thread manager */ + if (__pthread_threads_debug && __pthread_sig_debug > 0) + { + raise(__pthread_sig_debug); + /* We suspend ourself and gdb will wake us up when it is + ready to handle us. */ + __pthread_wait_for_restart_signal(thread_self()); + } + /* Synchronize debugging of the thread manager */ + PDEBUG("send REQ_DEBUG to manager thread\n"); + request.req_kind = REQ_DEBUG; + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); + return 0; +} + +/* Thread creation */ + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void * (*start_routine)(void *), void *arg) +{ + pthread_descr self = thread_self(); + struct pthread_request request; + if (__pthread_manager_request < 0) { + if (__pthread_initialize_manager() < 0) return EAGAIN; + } + request.req_thread = self; + request.req_kind = REQ_CREATE; + request.req_args.create.attr = attr; + request.req_args.create.fn = start_routine; + request.req_args.create.arg = arg; + sigprocmask(SIG_SETMASK, (const sigset_t *) NULL, + &request.req_args.create.mask); + PDEBUG("write REQ_CREATE to manager thread\n"); + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); + PDEBUG("before suspend(self)\n"); + suspend(self); + PDEBUG("after suspend(self)\n"); + if (THREAD_GETMEM(self, p_retcode) == 0) + *thread = (pthread_t) THREAD_GETMEM(self, p_retval); + return THREAD_GETMEM(self, p_retcode); +} + +/* Simple operations on thread identifiers */ + +pthread_t pthread_self(void) +{ + pthread_descr self = thread_self(); + return THREAD_GETMEM(self, p_tid); +} + +int pthread_equal(pthread_t thread1, pthread_t thread2) +{ + return thread1 == thread2; +} + +/* Helper function for thread_self in the case of user-provided stacks */ + +#ifndef THREAD_SELF + +pthread_descr __pthread_find_self() +{ + char * sp = CURRENT_STACK_FRAME; + pthread_handle h; + + /* __pthread_handles[0] is the initial thread, __pthread_handles[1] is + the manager threads handled specially in thread_self(), so start at 2 */ + h = __pthread_handles + 2; + while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++; + +#ifdef DEBUG_PT + if (h->h_descr == NULL) { + printf("*** %s ERROR descriptor is NULL!!!!! ***\n\n", __FUNCTION__); + _exit(1); + } +#endif + + return h->h_descr; +} +#else + +static pthread_descr thread_self_stack(void) +{ + char *sp = CURRENT_STACK_FRAME; + pthread_handle h; + + if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos) + return manager_thread; + h = __pthread_handles + 2; +# ifdef USE_TLS + while (h->h_descr == NULL + || ! (sp <= (char *) h->h_descr->p_stackaddr && sp >= h->h_bottom)) + h++; +# else + while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) + h++; +# endif + return h->h_descr; +} + +#endif + +/* Thread scheduling */ + +int pthread_setschedparam(pthread_t thread, int policy, + const struct sched_param *param) +{ + pthread_handle handle = thread_handle(thread); + pthread_descr th; + + __pthread_lock(&handle->h_lock, NULL); + if (invalid_handle(handle, thread)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + th = handle->h_descr; + if (sched_setscheduler(th->p_pid, policy, param) == -1) { + __pthread_unlock(&handle->h_lock); + return errno; + } + th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority; + __pthread_unlock(&handle->h_lock); + if (__pthread_manager_request >= 0) + __pthread_manager_adjust_prio(th->p_priority); + return 0; +} + +int pthread_getschedparam(pthread_t thread, int *policy, + struct sched_param *param) +{ + pthread_handle handle = thread_handle(thread); + int pid, pol; + + __pthread_lock(&handle->h_lock, NULL); + if (invalid_handle(handle, thread)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + pid = handle->h_descr->p_pid; + __pthread_unlock(&handle->h_lock); + pol = sched_getscheduler(pid); + if (pol == -1) return errno; + if (sched_getparam(pid, param) == -1) return errno; + *policy = pol; + return 0; +} + +/* Process-wide exit() request */ + +static void pthread_onexit_process(int retcode, void *arg) +{ + struct pthread_request request; + pthread_descr self = thread_self(); + + if (__pthread_manager_request >= 0) { + request.req_thread = self; + request.req_kind = REQ_PROCESS_EXIT; + request.req_args.exit.code = retcode; + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); + suspend(self); + /* Main thread should accumulate times for thread manager and its + children, so that timings for main thread account for all threads. */ + if (self == __pthread_main_thread) { + waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); + /* Since all threads have been asynchronously terminated + * (possibly holding locks), free cannot be used any more. */ + __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; + } + } +} + +/* The handler for the RESTART signal just records the signal received + in the thread descriptor, and optionally performs a siglongjmp + (for pthread_cond_timedwait). */ + +static void pthread_handle_sigrestart(int sig) +{ + pthread_descr self = thread_self(); + THREAD_SETMEM(self, p_signal, sig); + if (THREAD_GETMEM(self, p_signal_jmp) != NULL) + siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1); +} + +/* The handler for the CANCEL signal checks for cancellation + (in asynchronous mode), for process-wide exit and exec requests. + For the thread manager thread, redirect the signal to + __pthread_manager_sighandler. */ + +static void pthread_handle_sigcancel(int sig) +{ + pthread_descr self = thread_self(); + sigjmp_buf * jmpbuf; + + + if (self == &__pthread_manager_thread) + { +#ifdef THREAD_SELF + /* A new thread might get a cancel signal before it is fully + initialized, so that the thread register might still point to the + manager thread. Double check that this is really the manager + thread. */ + pthread_descr real_self = thread_self_stack(); + if (real_self == &__pthread_manager_thread) + { + __pthread_manager_sighandler(sig); + return; + } + /* Oops, thread_self() isn't working yet.. */ + self = real_self; +# ifdef INIT_THREAD_SELF + INIT_THREAD_SELF(self, self->p_nr); +# endif +#else + __pthread_manager_sighandler(sig); + return; +#endif + } + if (__builtin_expect (__pthread_exit_requested, 0)) { + /* Main thread should accumulate times for thread manager and its + children, so that timings for main thread account for all threads. */ + if (self == __pthread_main_thread) { +#ifdef USE_TLS + waitpid(__pthread_manager_thread->p_pid, NULL, __WCLONE); +#else + waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); +#endif + } + _exit(__pthread_exit_code); + } + if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) + pthread_exit(PTHREAD_CANCELED); + jmpbuf = THREAD_GETMEM(self, p_cancel_jmp); + if (jmpbuf != NULL) { + THREAD_SETMEM(self, p_cancel_jmp, NULL); + siglongjmp(*jmpbuf, 1); + } + } +} + +/* Handler for the DEBUG signal. + The debugging strategy is as follows: + On reception of a REQ_DEBUG request (sent by new threads created to + the thread manager under debugging mode), the thread manager throws + __pthread_sig_debug to itself. The debugger (if active) intercepts + this signal, takes into account new threads and continue execution + of the thread manager by propagating the signal because it doesn't + know what it is specifically done for. In the current implementation, + the thread manager simply discards it. */ + +static void pthread_handle_sigdebug(int sig) +{ + /* Nothing */ +} + +/* Reset the state of the thread machinery after a fork(). + Close the pipe used for requests and set the main thread to the forked + thread. + Notice that we can't free the stack segments, as the forked thread + may hold pointers into them. */ + +void __pthread_reset_main_thread() +{ + pthread_descr self = thread_self(); + + if (__pthread_manager_request != -1) { + /* Free the thread manager stack */ + free(__pthread_manager_thread_bos); + __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; + /* Close the two ends of the pipe */ + __libc_close(__pthread_manager_request); + __libc_close(__pthread_manager_reader); + __pthread_manager_request = __pthread_manager_reader = -1; + } + + /* Update the pid of the main thread */ + THREAD_SETMEM(self, p_pid, __getpid()); + /* Make the forked thread the main thread */ + __pthread_main_thread = self; + THREAD_SETMEM(self, p_nextlive, self); + THREAD_SETMEM(self, p_prevlive, self); + /* Now this thread modifies the global variables. */ + THREAD_SETMEM(self, p_errnop, &_errno); + THREAD_SETMEM(self, p_h_errnop, &_h_errno); +} + +/* Process-wide exec() request */ + +void __pthread_kill_other_threads_np(void) +{ + struct sigaction sa; + /* Terminate all other threads and thread manager */ + pthread_onexit_process(0, NULL); + /* Make current thread the main thread in case the calling thread + changes its mind, does not exec(), and creates new threads instead. */ + __pthread_reset_main_thread(); + /* Reset the signal handlers behaviour for the signals the + implementation uses since this would be passed to the new + process. */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_DFL; + __libc_sigaction(__pthread_sig_restart, &sa, NULL); + __libc_sigaction(__pthread_sig_cancel, &sa, NULL); + if (__pthread_sig_debug > 0) + __libc_sigaction(__pthread_sig_debug, &sa, NULL); +} +weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np) + +/* Concurrency symbol level. */ +static int current_level; + +int __pthread_setconcurrency(int level) +{ + /* We don't do anything unless we have found a useful interpretation. */ + current_level = level; + return 0; +} +weak_alias (__pthread_setconcurrency, pthread_setconcurrency) + +int __pthread_getconcurrency(void) +{ + return current_level; +} +weak_alias (__pthread_getconcurrency, pthread_getconcurrency) + + +/* Primitives for controlling thread execution */ + +void __pthread_wait_for_restart_signal(pthread_descr self) +{ + sigset_t mask; + + sigprocmask(SIG_SETMASK, NULL, &mask); /* Get current signal mask */ + sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */ + THREAD_SETMEM(self, p_signal, 0); + do { + sigsuspend(&mask); /* Wait for signal */ + } while (THREAD_GETMEM(self, p_signal) !=__pthread_sig_restart); + + READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */ +} + +#ifndef __NR_rt_sigaction +/* The _old variants are for 2.0 and early 2.1 kernels which don't have RT + signals. + On these kernels, we use SIGUSR1 and SIGUSR2 for restart and cancellation. + Since the restart signal does not queue, we use an atomic counter to create + queuing semantics. This is needed to resolve a rare race condition in + pthread_cond_timedwait_relative. */ + +void __pthread_restart_old(pthread_descr th) +{ + if (atomic_increment(&th->p_resume_count) == -1) + kill(th->p_pid, __pthread_sig_restart); +} + +void __pthread_suspend_old(pthread_descr self) +{ + if (atomic_decrement(&self->p_resume_count) <= 0) + __pthread_wait_for_restart_signal(self); +} + +int +__pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime) +{ + sigset_t unblock, initial_mask; + int was_signalled = 0; + sigjmp_buf jmpbuf; + + if (atomic_decrement(&self->p_resume_count) == 0) { + /* Set up a longjmp handler for the restart signal, unblock + the signal and sleep. */ + + if (sigsetjmp(jmpbuf, 1) == 0) { + THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); + THREAD_SETMEM(self, p_signal, 0); + /* Unblock the restart signal */ + sigemptyset(&unblock); + sigaddset(&unblock, __pthread_sig_restart); + sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); + + while (1) { + struct timeval now; + struct timespec reltime; + + /* Compute a time offset relative to now. */ + __gettimeofday (&now, NULL); + reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; + reltime.tv_sec = abstime->tv_sec - now.tv_sec; + if (reltime.tv_nsec < 0) { + reltime.tv_nsec += 1000000000; + reltime.tv_sec -= 1; + } + + /* Sleep for the required duration. If woken by a signal, + resume waiting as required by Single Unix Specification. */ + if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) + break; + } + + /* Block the restart signal again */ + sigprocmask(SIG_SETMASK, &initial_mask, NULL); + was_signalled = 0; + } else { + was_signalled = 1; + } + THREAD_SETMEM(self, p_signal_jmp, NULL); + } + + /* Now was_signalled is true if we exited the above code + due to the delivery of a restart signal. In that case, + we know we have been dequeued and resumed and that the + resume count is balanced. Otherwise, there are some + cases to consider. First, try to bump up the resume count + back to zero. If it goes to 1, it means restart() was + invoked on this thread. The signal must be consumed + and the count bumped down and everything is cool. We + can return a 1 to the caller. + Otherwise, no restart was delivered yet, so a potential + race exists; we return a 0 to the caller which must deal + with this race in an appropriate way; for example by + atomically removing the thread from consideration for a + wakeup---if such a thing fails, it means a restart is + being delivered. */ + + if (!was_signalled) { + if (atomic_increment(&self->p_resume_count) != -1) { + __pthread_wait_for_restart_signal(self); + atomic_decrement(&self->p_resume_count); /* should be zero now! */ + /* woke spontaneously and consumed restart signal */ + return 1; + } + /* woke spontaneously but did not consume restart---caller must resolve */ + return 0; + } + /* woken due to restart signal */ + return 1; +} +#endif /* __NR_rt_sigaction */ + + +#ifdef __NR_rt_sigaction +void __pthread_restart_new(pthread_descr th) +{ + /* The barrier is proabably not needed, in which case it still documents + our assumptions. The intent is to commit previous writes to shared + memory so the woken thread will have a consistent view. Complementary + read barriers are present to the suspend functions. */ + WRITE_MEMORY_BARRIER(); + kill(th->p_pid, __pthread_sig_restart); +} + +int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime) +{ + sigset_t unblock, initial_mask; + int was_signalled = 0; + sigjmp_buf jmpbuf; + + if (sigsetjmp(jmpbuf, 1) == 0) { + THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); + THREAD_SETMEM(self, p_signal, 0); + /* Unblock the restart signal */ + sigemptyset(&unblock); + sigaddset(&unblock, __pthread_sig_restart); + sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); + + while (1) { + struct timeval now; + struct timespec reltime; + + /* Compute a time offset relative to now. */ + gettimeofday (&now, NULL); + reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; + reltime.tv_sec = abstime->tv_sec - now.tv_sec; + if (reltime.tv_nsec < 0) { + reltime.tv_nsec += 1000000000; + reltime.tv_sec -= 1; + } + + /* Sleep for the required duration. If woken by a signal, + resume waiting as required by Single Unix Specification. */ + if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) + break; + } + + /* Block the restart signal again */ + sigprocmask(SIG_SETMASK, &initial_mask, NULL); + was_signalled = 0; + } else { + was_signalled = 1; + } + THREAD_SETMEM(self, p_signal_jmp, NULL); + + /* Now was_signalled is true if we exited the above code + due to the delivery of a restart signal. In that case, + everything is cool. We have been removed from whatever + we were waiting on by the other thread, and consumed its signal. + + Otherwise we this thread woke up spontaneously, or due to a signal other + than restart. This is an ambiguous case that must be resolved by + the caller; the thread is still eligible for a restart wakeup + so there is a race. */ + + READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */ + return was_signalled; +} +#endif + +/* Debugging aid */ + +#ifdef DEBUG_PT +#include + +void __pthread_message(char * fmt, ...) +{ + char buffer[1024]; + va_list args; + sprintf(buffer, "%05d : ", __getpid()); + va_start(args, fmt); + vsnprintf(buffer + 8, sizeof(buffer) - 8, fmt, args); + va_end(args); + TEMP_FAILURE_RETRY(__libc_write(2, buffer, strlen(buffer))); +} + +#endif + + +#ifndef __PIC__ +/* We need a hook to force the cancelation wrappers to be linked in when + static libpthread is used. */ +extern const int __pthread_provide_wrappers; +static const int *const __pthread_require_wrappers = + &__pthread_provide_wrappers; +#endif diff --git a/libpthread/linuxthreads.old/pthread.c-OLDEXAMPLE b/libpthread/linuxthreads.old/pthread.c-OLDEXAMPLE new file mode 100644 index 000000000..88b163087 --- /dev/null +++ b/libpthread/linuxthreads.old/pthread.c-OLDEXAMPLE @@ -0,0 +1,121 @@ +/* vi: set sw=4 ts=4: */ +/* + * A _very_ simple clone based pthread-like implementation + * + * Copyright (C) 2001,2002 by Erik Andersen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License + * for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#define STACKSIZE 8096 + +#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ +#define CLONE_VM 0x00000100 /* set if VM shared between processes */ +#define CLONE_FS 0x00000200 /* set if fs info shared between proces ses */ +#define CLONE_FILES 0x00000400 /* set if open files shared between pro cesses */ +#define CLONE_SIGHAND 0x00000800 /* set if signal handlers shared */ + + + +/* Lame home-grown clone based threading */ +int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutex_attr) +{ + mutex->__m_lock.__spinlock = 1; + return 0; +} + +int pthread_mutex_lock (pthread_mutex_t *mutex) +{ + while (mutex->__m_lock.__spinlock == 0) { + usleep(10000); + } + --(mutex->__m_lock.__spinlock); + return 0; +} + +int pthread_mutex_unlock (pthread_mutex_t *mutex) +{ + ++(mutex->__m_lock.__spinlock); + return 0; +} + +int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + ++(mutex->__m_lock.__spinlock); + while (cond->__c_lock.__spinlock == 0) { + usleep(10000); + } + --(cond->__c_lock.__spinlock); + return 0; +} + +int pthread_cond_signal(pthread_cond_t *cond) +{ + ++(cond->__c_lock.__spinlock); + return 0; +} + +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) +{ + cond->__c_lock.__spinlock = 1; + return 0; +} + +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void* (*fn)(void *), void *data) +{ + long retval; + void **newstack; + int (*clonefunc)(void *) = (int (*)(void *))(fn); + + newstack = (void **) malloc(STACKSIZE); + if (!newstack) + return -1; + newstack = (void **) (STACKSIZE + (char *) newstack); + *--newstack = data; + retval = clone(clonefunc, newstack, + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD, data); + if (retval < 0) { + errno = -retval; + *thread = 0; + retval = -1; + } else { + *thread = retval; + retval = 0; + } + return retval; +} + +int pthread_join (pthread_t thread, void **thread_return) +{ + int retval; + /* Fixme -- wait for thread and get its return value */ + retval = EXIT_SUCCESS; + if (thread_return) + (int)*thread_return = retval; + _exit(retval); +} +link_warning(pthread_join, "pthread_join is a stub and does not behave properly"); + +void pthread_exit (void *retval) +{ + _exit(*(int *)retval); +} diff --git a/libpthread/linuxthreads.old/ptlongjmp.c b/libpthread/linuxthreads.old/ptlongjmp.c new file mode 100644 index 000000000..c0ea8223a --- /dev/null +++ b/libpthread/linuxthreads.old/ptlongjmp.c @@ -0,0 +1,55 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Redefine siglongjmp and longjmp so that they interact correctly + with cleanup handlers */ + +#include +#include "pthread.h" +#include "internals.h" + +/* These functions are not declared anywhere since they shouldn't be + used at another place but here. */ +extern void __libc_siglongjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); +extern void __libc_longjmp (sigjmp_buf env, int val) + __attribute__ ((noreturn)); + + +static void pthread_cleanup_upto(__jmp_buf target) +{ + pthread_descr self = thread_self(); + struct _pthread_cleanup_buffer * c; + + for (c = THREAD_GETMEM(self, p_cleanup); + c != NULL && _JMPBUF_UNWINDS(target, c); + c = c->__prev) + c->__routine(c->__arg); + THREAD_SETMEM(self, p_cleanup, c); + if (THREAD_GETMEM(self, p_in_sighandler) + && _JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler))) + THREAD_SETMEM(self, p_in_sighandler, NULL); +} + +void siglongjmp(sigjmp_buf env, int val) +{ + pthread_cleanup_upto(env->__jmpbuf); + __libc_siglongjmp(env, val); +} + +void longjmp(jmp_buf env, int val) +{ + pthread_cleanup_upto(env->__jmpbuf); + __libc_siglongjmp(env, val); +} diff --git a/libpthread/linuxthreads.old/queue.h b/libpthread/linuxthreads.old/queue.h new file mode 100644 index 000000000..28bd75531 --- /dev/null +++ b/libpthread/linuxthreads.old/queue.h @@ -0,0 +1,61 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Waiting queues */ + +/* Waiting queues are represented by lists of thread descriptors + linked through their p_nextwaiting field. The lists are kept + sorted by decreasing priority, and then decreasing waiting time. */ + +static inline void enqueue(pthread_descr * q, pthread_descr th) +{ + int prio = th->p_priority; + ASSERT(th->p_nextwaiting == NULL); + for (; *q != NULL; q = &((*q)->p_nextwaiting)) { + if (prio > (*q)->p_priority) { + th->p_nextwaiting = *q; + *q = th; + return; + } + } + *q = th; +} + +static inline pthread_descr dequeue(pthread_descr * q) +{ + pthread_descr th; + th = *q; + if (th != NULL) { + *q = th->p_nextwaiting; + th->p_nextwaiting = NULL; + } + return th; +} + +static inline int remove_from_queue(pthread_descr * q, pthread_descr th) +{ + for (; *q != NULL; q = &((*q)->p_nextwaiting)) { + if (*q == th) { + *q = th->p_nextwaiting; + th->p_nextwaiting = NULL; + return 1; + } + } + return 0; +} + +static inline int queue_is_empty(pthread_descr * q) +{ + return *q == NULL; +} diff --git a/libpthread/linuxthreads.old/restart.h b/libpthread/linuxthreads.old/restart.h new file mode 100644 index 000000000..687d92fae --- /dev/null +++ b/libpthread/linuxthreads.old/restart.h @@ -0,0 +1,50 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#include +#include +#define __ASSUME_REALTIME_SIGNALS defined(__NR_rt_sigaction) + +/* Primitives for controlling thread execution */ + +static inline void restart(pthread_descr th) +{ + /* See pthread.c */ +#if __ASSUME_REALTIME_SIGNALS + __pthread_restart_new(th); +#else + __pthread_restart(th); +#endif +} + +static inline void suspend(pthread_descr self) +{ + /* See pthread.c */ +#if __ASSUME_REALTIME_SIGNALS + __pthread_wait_for_restart_signal(self); +#else + __pthread_suspend(self); +#endif +} + +static inline int timedsuspend(pthread_descr self, + const struct timespec *abstime) +{ + /* See pthread.c */ +#if __ASSUME_REALTIME_SIGNALS + return __pthread_timedsuspend_new(self, abstime); +#else + return __pthread_timedsuspend(self, abstime); +#endif +} diff --git a/libpthread/linuxthreads.old/rwlock.c b/libpthread/linuxthreads.old/rwlock.c new file mode 100644 index 000000000..977fd88af --- /dev/null +++ b/libpthread/linuxthreads.old/rwlock.c @@ -0,0 +1,486 @@ +/* Read-write lock implementation. + Copyright (C) 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Xavier Leroy + and Ulrich Drepper , 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include "internals.h" +#include "queue.h" +#include "spinlock.h" +#include "restart.h" + +/* + * Check whether the calling thread already owns one or more read locks on the + * specified lock. If so, return a pointer to the read lock info structure + * corresponding to that lock. + */ + +static pthread_readlock_info * +rwlock_is_in_list(pthread_descr self, pthread_rwlock_t *rwlock) +{ + pthread_readlock_info *info; + + for (info = self->p_readlock_list; info != NULL; info = info->pr_next) + { + if (info->pr_lock == rwlock) + return info; + } + + return NULL; +} + +/* + * Add a new lock to the thread's list of locks for which it has a read lock. + * A new info node must be allocated for this, which is taken from the thread's + * free list, or by calling malloc. If malloc fails, a null pointer is + * returned. Otherwise the lock info structure is initialized and pushed + * onto the thread's list. + */ + +static pthread_readlock_info * +rwlock_add_to_list(pthread_descr self, pthread_rwlock_t *rwlock) +{ + pthread_readlock_info *info = self->p_readlock_free; + + if (info != NULL) + self->p_readlock_free = info->pr_next; + else + info = malloc(sizeof *info); + + if (info == NULL) + return NULL; + + info->pr_lock_count = 1; + info->pr_lock = rwlock; + info->pr_next = self->p_readlock_list; + self->p_readlock_list = info; + + return info; +} + +/* + * If the thread owns a read lock over the given pthread_rwlock_t, + * and this read lock is tracked in the thread's lock list, + * this function returns a pointer to the info node in that list. + * It also decrements the lock count within that node, and if + * it reaches zero, it removes the node from the list. + * If nothing is found, it returns a null pointer. + */ + +static pthread_readlock_info * +rwlock_remove_from_list(pthread_descr self, pthread_rwlock_t *rwlock) +{ + pthread_readlock_info **pinfo; + + for (pinfo = &self->p_readlock_list; *pinfo != NULL; pinfo = &(*pinfo)->pr_next) + { + if ((*pinfo)->pr_lock == rwlock) + { + pthread_readlock_info *info = *pinfo; + if (--info->pr_lock_count == 0) + *pinfo = info->pr_next; + return info; + } + } + + return NULL; +} + +/* + * This function checks whether the conditions are right to place a read lock. + * It returns 1 if so, otherwise zero. The rwlock's internal lock must be + * locked upon entry. + */ + +static int +rwlock_can_rdlock(pthread_rwlock_t *rwlock, int have_lock_already) +{ + /* Can't readlock; it is write locked. */ + if (rwlock->__rw_writer != NULL) + return 0; + + /* Lock prefers readers; get it. */ + if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP) + return 1; + + /* Lock prefers writers, but none are waiting. */ + if (queue_is_empty(&rwlock->__rw_write_waiting)) + return 1; + + /* Writers are waiting, but this thread already has a read lock */ + if (have_lock_already) + return 1; + + /* Writers are waiting, and this is a new lock */ + return 0; +} + +/* + * This function helps support brain-damaged recursive read locking + * semantics required by Unix 98, while maintaining write priority. + * This basically determines whether this thread already holds a read lock + * already. It returns 1 if so, otherwise it returns 0. + * + * If the thread has any ``untracked read locks'' then it just assumes + * that this lock is among them, just to be safe, and returns 1. + * + * Also, if it finds the thread's lock in the list, it sets the pointer + * referenced by pexisting to refer to the list entry. + * + * If the thread has no untracked locks, and the lock is not found + * in its list, then it is added to the list. If this fails, + * then *pout_of_mem is set to 1. + */ + +static int +rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock, + pthread_readlock_info **pexisting, int *pout_of_mem) +{ + pthread_readlock_info *existing = NULL; + int out_of_mem = 0, have_lock_already = 0; + pthread_descr self = *pself; + + if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP) + { + if (!self) + self = thread_self(); + + existing = rwlock_is_in_list(self, rwlock); + + if (existing != NULL || self->p_untracked_readlock_count > 0) + have_lock_already = 1; + else + { + existing = rwlock_add_to_list(self, rwlock); + if (existing == NULL) + out_of_mem = 1; + } + } + + *pout_of_mem = out_of_mem; + *pexisting = existing; + *pself = self; + + return have_lock_already; +} + +int +pthread_rwlock_init (pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + __pthread_init_lock(&rwlock->__rw_lock); + rwlock->__rw_readers = 0; + rwlock->__rw_writer = NULL; + rwlock->__rw_read_waiting = NULL; + rwlock->__rw_write_waiting = NULL; + + if (attr == NULL) + { + rwlock->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP; + rwlock->__rw_pshared = PTHREAD_PROCESS_PRIVATE; + } + else + { + rwlock->__rw_kind = attr->__lockkind; + rwlock->__rw_pshared = attr->__pshared; + } + + return 0; +} + + +int +pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int readers; + _pthread_descr writer; + + __pthread_lock (&rwlock->__rw_lock, NULL); + readers = rwlock->__rw_readers; + writer = rwlock->__rw_writer; + __pthread_unlock (&rwlock->__rw_lock); + + if (readers > 0 || writer != NULL) + return EBUSY; + + return 0; +} + +int +pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + pthread_descr self = NULL; + pthread_readlock_info *existing; + int out_of_mem, have_lock_already; + + have_lock_already = rwlock_have_already(&self, rwlock, + &existing, &out_of_mem); + + for (;;) + { + if (self == NULL) + self = thread_self (); + + __pthread_lock (&rwlock->__rw_lock, self); + + if (rwlock_can_rdlock(rwlock, have_lock_already)) + break; + + enqueue (&rwlock->__rw_read_waiting, self); + __pthread_unlock (&rwlock->__rw_lock); + suspend (self); /* This is not a cancellation point */ + } + + ++rwlock->__rw_readers; + __pthread_unlock (&rwlock->__rw_lock); + + if (have_lock_already || out_of_mem) + { + if (existing != NULL) + existing->pr_lock_count++; + else + self->p_untracked_readlock_count++; + } + + return 0; +} + +int +pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + pthread_descr self = thread_self(); + pthread_readlock_info *existing; + int out_of_mem, have_lock_already; + int retval = EBUSY; + + have_lock_already = rwlock_have_already(&self, rwlock, + &existing, &out_of_mem); + + __pthread_lock (&rwlock->__rw_lock, self); + + /* 0 is passed to here instead of have_lock_already. + This is to meet Single Unix Spec requirements: + if writers are waiting, pthread_rwlock_tryrdlock + does not acquire a read lock, even if the caller has + one or more read locks already. */ + + if (rwlock_can_rdlock(rwlock, 0)) + { + ++rwlock->__rw_readers; + retval = 0; + } + + __pthread_unlock (&rwlock->__rw_lock); + + if (retval == 0) + { + if (have_lock_already || out_of_mem) + { + if (existing != NULL) + existing->pr_lock_count++; + else + self->p_untracked_readlock_count++; + } + } + + return retval; +} + + +int +pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + pthread_descr self = thread_self (); + + while(1) + { + __pthread_lock (&rwlock->__rw_lock, self); + if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) + { + rwlock->__rw_writer = self; + __pthread_unlock (&rwlock->__rw_lock); + return 0; + } + + /* Suspend ourselves, then try again */ + enqueue (&rwlock->__rw_write_waiting, self); + __pthread_unlock (&rwlock->__rw_lock); + suspend (self); /* This is not a cancellation point */ + } +} + + +int +pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + int result = EBUSY; + + __pthread_lock (&rwlock->__rw_lock, NULL); + if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) + { + rwlock->__rw_writer = thread_self (); + result = 0; + } + __pthread_unlock (&rwlock->__rw_lock); + + return result; +} + + +int +pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + pthread_descr torestart; + pthread_descr th; + + __pthread_lock (&rwlock->__rw_lock, NULL); + if (rwlock->__rw_writer != NULL) + { + /* Unlocking a write lock. */ + if (rwlock->__rw_writer != thread_self ()) + { + __pthread_unlock (&rwlock->__rw_lock); + return EPERM; + } + rwlock->__rw_writer = NULL; + + if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP + || (th = dequeue (&rwlock->__rw_write_waiting)) == NULL) + { + /* Restart all waiting readers. */ + torestart = rwlock->__rw_read_waiting; + rwlock->__rw_read_waiting = NULL; + __pthread_unlock (&rwlock->__rw_lock); + while ((th = dequeue (&torestart)) != NULL) + restart (th); + } + else + { + /* Restart one waiting writer. */ + __pthread_unlock (&rwlock->__rw_lock); + restart (th); + } + } + else + { + /* Unlocking a read lock. */ + if (rwlock->__rw_readers == 0) + { + __pthread_unlock (&rwlock->__rw_lock); + return EPERM; + } + + --rwlock->__rw_readers; + if (rwlock->__rw_readers == 0) + /* Restart one waiting writer, if any. */ + th = dequeue (&rwlock->__rw_write_waiting); + else + th = NULL; + + __pthread_unlock (&rwlock->__rw_lock); + if (th != NULL) + restart (th); + + /* Recursive lock fixup */ + + if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP) + { + pthread_descr self = thread_self(); + pthread_readlock_info *victim = rwlock_remove_from_list(self, rwlock); + + if (victim != NULL) + { + if (victim->pr_lock_count == 0) + { + victim->pr_next = self->p_readlock_free; + self->p_readlock_free = victim; + } + } + else + { + if (self->p_untracked_readlock_count > 0) + self->p_untracked_readlock_count--; + } + } + } + + return 0; +} + + + +int +pthread_rwlockattr_init (pthread_rwlockattr_t *attr) +{ + attr->__lockkind = 0; + attr->__pshared = 0; + + return 0; +} + + +int +pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr) +{ + return 0; +} + + +int +pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared) +{ + *pshared = attr->__pshared; + return 0; +} + + +int +pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) +{ + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; + + attr->__pshared = pshared; + + return 0; +} + + +int +pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref) +{ + *pref = attr->__lockkind; + return 0; +} + + +int +pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref) +{ + if (pref != PTHREAD_RWLOCK_PREFER_READER_NP + && pref != PTHREAD_RWLOCK_PREFER_WRITER_NP + && pref != PTHREAD_RWLOCK_DEFAULT_NP) + return EINVAL; + + attr->__lockkind = pref; + + return 0; +} diff --git a/libpthread/linuxthreads.old/semaphore.c b/libpthread/linuxthreads.old/semaphore.c new file mode 100644 index 000000000..5be1f5316 --- /dev/null +++ b/libpthread/linuxthreads.old/semaphore.c @@ -0,0 +1,308 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Semaphores a la POSIX 1003.1b */ + +#include +#define __USE_GNU +#include +#include "pthread.h" +#include "semaphore.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" +#include "queue.h" + +int __new_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return -1; + } + if (pshared) { + errno = ENOSYS; + return -1; + } + __pthread_init_lock(&sem->__sem_lock); + sem->__sem_value = value; + sem->__sem_waiting = NULL; + return 0; +} + +/* Function called by pthread_cancel to remove the thread from + waiting inside __new_sem_wait. */ + +static int new_sem_extricate_func(void *obj, pthread_descr th) +{ + volatile pthread_descr self = thread_self(); + sem_t *sem = obj; + int did_remove = 0; + + __pthread_lock(&sem->__sem_lock, self); + did_remove = remove_from_queue(&sem->__sem_waiting, th); + __pthread_unlock(&sem->__sem_lock); + + return did_remove; +} + +int __new_sem_wait(sem_t * sem) +{ + volatile pthread_descr self = thread_self(); + pthread_extricate_if extr; + int already_canceled = 0; + int spurious_wakeup_count; + + /* Set up extrication interface */ + extr.pu_object = sem; + extr.pu_extricate_func = new_sem_extricate_func; + + __pthread_lock(&sem->__sem_lock, self); + if (sem->__sem_value > 0) { + sem->__sem_value--; + __pthread_unlock(&sem->__sem_lock); + return 0; + } + /* Register extrication interface */ + THREAD_SETMEM(self, p_sem_avail, 0); + __pthread_set_own_extricate_if(self, &extr); + /* Enqueue only if not already cancelled. */ + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + enqueue(&sem->__sem_waiting, self); + else + already_canceled = 1; + __pthread_unlock(&sem->__sem_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + pthread_exit(PTHREAD_CANCELED); + } + + /* Wait for sem_post or cancellation, or fall through if already canceled */ + spurious_wakeup_count = 0; + while (1) + { + suspend(self); + if (THREAD_GETMEM(self, p_sem_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + __pthread_set_own_extricate_if(self, 0); + + /* Terminate only if the wakeup came from cancellation. */ + /* Otherwise ignore cancellation because we got the semaphore. */ + + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + pthread_exit(PTHREAD_CANCELED); + } + /* We got the semaphore */ + return 0; +} + +int __new_sem_trywait(sem_t * sem) +{ + int retval; + + __pthread_lock(&sem->__sem_lock, NULL); + if (sem->__sem_value == 0) { + errno = EAGAIN; + retval = -1; + } else { + sem->__sem_value--; + retval = 0; + } + __pthread_unlock(&sem->__sem_lock); + return retval; +} + +int __new_sem_post(sem_t * sem) +{ + pthread_descr self = thread_self(); + pthread_descr th; + struct pthread_request request; + + if (THREAD_GETMEM(self, p_in_sighandler) == NULL) { + __pthread_lock(&sem->__sem_lock, self); + if (sem->__sem_waiting == NULL) { + if (sem->__sem_value >= SEM_VALUE_MAX) { + /* Overflow */ + errno = ERANGE; + __pthread_unlock(&sem->__sem_lock); + return -1; + } + sem->__sem_value++; + __pthread_unlock(&sem->__sem_lock); + } else { + th = dequeue(&sem->__sem_waiting); + __pthread_unlock(&sem->__sem_lock); + th->p_sem_avail = 1; + WRITE_MEMORY_BARRIER(); + restart(th); + } + } else { + /* If we're in signal handler, delegate post operation to + the thread manager. */ + if (__pthread_manager_request < 0) { + if (__pthread_initialize_manager() < 0) { + errno = EAGAIN; + return -1; + } + } + request.req_kind = REQ_POST; + request.req_args.post = sem; + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); + } + return 0; +} + +int __new_sem_getvalue(sem_t * sem, int * sval) +{ + *sval = sem->__sem_value; + return 0; +} + +int __new_sem_destroy(sem_t * sem) +{ + if (sem->__sem_waiting != NULL) { + __set_errno (EBUSY); + return -1; + } + return 0; +} + +sem_t *sem_open(const char *name, int oflag, ...) +{ + __set_errno (ENOSYS); + return SEM_FAILED; +} + +int sem_close(sem_t *sem) +{ + __set_errno (ENOSYS); + return -1; +} + +int sem_unlink(const char *name) +{ + __set_errno (ENOSYS); + return -1; +} + +int sem_timedwait(sem_t *sem, const struct timespec *abstime) +{ + pthread_descr self = thread_self(); + pthread_extricate_if extr; + int already_canceled = 0; + int spurious_wakeup_count; + + __pthread_lock(&sem->__sem_lock, self); + if (sem->__sem_value > 0) { + --sem->__sem_value; + __pthread_unlock(&sem->__sem_lock); + return 0; + } + + if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) { + /* The standard requires that if the function would block and the + time value is illegal, the function returns with an error. */ + __pthread_unlock(&sem->__sem_lock); + __set_errno (EINVAL); + return -1; + } + + /* Set up extrication interface */ + extr.pu_object = sem; + extr.pu_extricate_func = new_sem_extricate_func; + + /* Register extrication interface */ + THREAD_SETMEM(self, p_sem_avail, 0); + __pthread_set_own_extricate_if(self, &extr); + /* Enqueue only if not already cancelled. */ + if (!(THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) + enqueue(&sem->__sem_waiting, self); + else + already_canceled = 1; + __pthread_unlock(&sem->__sem_lock); + + if (already_canceled) { + __pthread_set_own_extricate_if(self, 0); + pthread_exit(PTHREAD_CANCELED); + } + + spurious_wakeup_count = 0; + while (1) + { + if (timedsuspend(self, abstime) == 0) { + int was_on_queue; + + /* __pthread_lock will queue back any spurious restarts that + may happen to it. */ + + __pthread_lock(&sem->__sem_lock, self); + was_on_queue = remove_from_queue(&sem->__sem_waiting, self); + __pthread_unlock(&sem->__sem_lock); + + if (was_on_queue) { + __pthread_set_own_extricate_if(self, 0); + __set_errno (ETIMEDOUT); + return -1; + } + + /* Eat the outstanding restart() from the signaller */ + suspend(self); + } + + if (THREAD_GETMEM(self, p_sem_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + + __pthread_set_own_extricate_if(self, 0); + + /* Terminate only if the wakeup came from cancellation. */ + /* Otherwise ignore cancellation because we got the semaphore. */ + + if (THREAD_GETMEM(self, p_woken_by_cancel) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { + THREAD_SETMEM(self, p_woken_by_cancel, 0); + pthread_exit(PTHREAD_CANCELED); + } + /* We got the semaphore */ + return 0; +} + + +weak_alias (__new_sem_init, sem_init) +weak_alias (__new_sem_wait, sem_wait) +weak_alias (__new_sem_trywait, sem_trywait) +weak_alias (__new_sem_post, sem_post) +weak_alias (__new_sem_getvalue, sem_getvalue) +weak_alias (__new_sem_destroy, sem_destroy) + diff --git a/libpthread/linuxthreads.old/semaphore.h b/libpthread/linuxthreads.old/semaphore.h new file mode 100644 index 000000000..7b09ea931 --- /dev/null +++ b/libpthread/linuxthreads.old/semaphore.h @@ -0,0 +1,87 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#ifndef _SEMAPHORE_H +#define _SEMAPHORE_H 1 + +#include +#include +#ifdef __USE_XOPEN2K +# define __need_timespec +# include +#endif + +#ifndef _PTHREAD_DESCR_DEFINED +/* Thread descriptors. Needed for `sem_t' definition. */ +typedef struct _pthread_descr_struct *_pthread_descr; +# define _PTHREAD_DESCR_DEFINED +#endif + +/* System specific semaphore definition. */ +typedef struct +{ + struct _pthread_fastlock __sem_lock; + int __sem_value; + _pthread_descr __sem_waiting; +} sem_t; + + + +/* Value returned if `sem_open' failed. */ +#define SEM_FAILED ((sem_t *) 0) + +/* Maximum value the semaphore can have. */ +#define SEM_VALUE_MAX ((int) ((~0u) >> 1)) + + +__BEGIN_DECLS + +/* Initialize semaphore object SEM to VALUE. If PSHARED then share it + with other processes. */ +extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value) __THROW; + +/* Free resources associated with semaphore object SEM. */ +extern int sem_destroy (sem_t *__sem) __THROW; + +/* Open a named semaphore NAME with open flaot OFLAG. */ +extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW; + +/* Close descriptor for named semaphore SEM. */ +extern int sem_close (sem_t *__sem) __THROW; + +/* Remove named semaphore NAME. */ +extern int sem_unlink (__const char *__name) __THROW; + +/* Wait for SEM being posted. */ +extern int sem_wait (sem_t *__sem); + +#ifdef __USE_XOPEN2K +/* Similar to `sem_wait' but wait only until ABSTIME. */ +extern int sem_timedwait (sem_t *__restrict __sem, + __const struct timespec *__restrict __abstime); +#endif + +/* Test whether SEM is posted. */ +extern int sem_trywait (sem_t *__sem) __THROW; + +/* Post SEM. */ +extern int sem_post (sem_t *__sem) __THROW; + +/* Get current value of SEM and store it in *SVAL. */ +extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval) + __THROW; + +__END_DECLS + +#endif /* semaphore.h */ diff --git a/libpthread/linuxthreads.old/signals.c b/libpthread/linuxthreads.old/signals.c new file mode 100644 index 000000000..df15b884e --- /dev/null +++ b/libpthread/linuxthreads.old/signals.c @@ -0,0 +1,248 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Handling of signals */ + +#include +#include +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include +#include + +/* mods for uClibc: __libc_sigaction is not in any standard headers */ +extern int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact); + +int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask) +{ + sigset_t mask; + + if (newmask != NULL) { + mask = *newmask; + /* Don't allow __pthread_sig_restart to be unmasked. + Don't allow __pthread_sig_cancel to be masked. */ + switch(how) { + case SIG_SETMASK: + sigaddset(&mask, __pthread_sig_restart); + sigdelset(&mask, __pthread_sig_cancel); + if (__pthread_sig_debug > 0) + sigdelset(&mask, __pthread_sig_debug); + break; + case SIG_BLOCK: + sigdelset(&mask, __pthread_sig_cancel); + if (__pthread_sig_debug > 0) + sigdelset(&mask, __pthread_sig_debug); + break; + case SIG_UNBLOCK: + sigdelset(&mask, __pthread_sig_restart); + break; + } + newmask = &mask; + } + if (sigprocmask(how, newmask, oldmask) == -1) + return errno; + else + return 0; +} + +int pthread_kill(pthread_t thread, int signo) +{ + pthread_handle handle = thread_handle(thread); + int pid; + + __pthread_lock(&handle->h_lock, NULL); + if (invalid_handle(handle, thread)) { + __pthread_unlock(&handle->h_lock); + return ESRCH; + } + pid = handle->h_descr->p_pid; + __pthread_unlock(&handle->h_lock); + if (kill(pid, signo) == -1) + return errno; + else + return 0; +} + +/* User-provided signal handlers */ +typedef void (*arch_sighandler_t) __PMT ((int, SIGCONTEXT)); +static union +{ + arch_sighandler_t old; + void (*rt) (int, struct siginfo *, struct ucontext *); +} sighandler[NSIG]; + +/* The wrapper around user-provided signal handlers */ +static void pthread_sighandler(int signo, SIGCONTEXT ctx) +{ + pthread_descr self = thread_self(); + char * in_sighandler; + /* If we're in a sigwait operation, just record the signal received + and return without calling the user's handler */ + if (THREAD_GETMEM(self, p_sigwaiting)) { + THREAD_SETMEM(self, p_sigwaiting, 0); + THREAD_SETMEM(self, p_signal, signo); + return; + } + /* Record that we're in a signal handler and call the user's + handler function */ + in_sighandler = THREAD_GETMEM(self, p_in_sighandler); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); + sighandler[signo].old(signo, SIGCONTEXT_EXTRA_ARGS ctx); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, NULL); +} + +/* The same, this time for real-time signals. */ +static void pthread_sighandler_rt(int signo, struct siginfo *si, + struct ucontext *uc) +{ + pthread_descr self = thread_self(); + char * in_sighandler; + /* If we're in a sigwait operation, just record the signal received + and return without calling the user's handler */ + if (THREAD_GETMEM(self, p_sigwaiting)) { + THREAD_SETMEM(self, p_sigwaiting, 0); + THREAD_SETMEM(self, p_signal, signo); + return; + } + /* Record that we're in a signal handler and call the user's + handler function */ + in_sighandler = THREAD_GETMEM(self, p_in_sighandler); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); + sighandler[signo].rt(signo, si, uc); + if (in_sighandler == NULL) + THREAD_SETMEM(self, p_in_sighandler, NULL); +} + +/* The wrapper around sigaction. Install our own signal handler + around the signal. */ +int __sigaction(int sig, const struct sigaction * act, + struct sigaction * oact) +{ + struct sigaction newact; + struct sigaction *newactp; + +#ifdef DEBUG_PT +printf(__FUNCTION__": pthreads wrapper!\n"); +#endif + if (sig == __pthread_sig_restart || + sig == __pthread_sig_cancel || + (sig == __pthread_sig_debug && __pthread_sig_debug > 0)) + return EINVAL; + if (act) + { + newact = *act; + if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL + && sig > 0 && sig < NSIG) + { + if (act->sa_flags & SA_SIGINFO) + newact.sa_handler = (__sighandler_t) pthread_sighandler_rt; + else + newact.sa_handler = (__sighandler_t) pthread_sighandler; + } + newactp = &newact; + } + else + newactp = NULL; + if (__libc_sigaction(sig, newactp, oact) == -1) + return -1; +#ifdef DEBUG_PT +printf(__FUNCTION__": signahdler installed, __sigaction successful\n"); +#endif + if (sig > 0 && sig < NSIG) + { + if (oact != NULL) + oact->sa_handler = (__sighandler_t) sighandler[sig].old; + if (act) + /* For the assignment is does not matter whether it's a normal + or real-time signal. */ + sighandler[sig].old = (arch_sighandler_t) act->sa_handler; + } + return 0; +} +strong_alias(__sigaction, sigaction) + +/* A signal handler that does nothing */ +static void pthread_null_sighandler(int sig) { } + +/* sigwait -- synchronously wait for a signal */ +int sigwait(const sigset_t * set, int * sig) +{ + volatile pthread_descr self = thread_self(); + sigset_t mask; + int s; + sigjmp_buf jmpbuf; + struct sigaction sa; + + /* Get ready to block all signals except those in set + and the cancellation signal. + Also check that handlers are installed on all signals in set, + and if not, install our dummy handler. This is conformant to + POSIX: "The effect of sigwait() on the signal actions for the + signals in set is unspecified." */ + sigfillset(&mask); + sigdelset(&mask, __pthread_sig_cancel); + for (s = 1; s <= NSIG; s++) { + if (sigismember(set, s) && + s != __pthread_sig_restart && + s != __pthread_sig_cancel && + s != __pthread_sig_debug) { + sigdelset(&mask, s); + if (sighandler[s].old == NULL || + sighandler[s].old == (arch_sighandler_t) SIG_DFL || + sighandler[s].old == (arch_sighandler_t) SIG_IGN) { + sa.sa_handler = pthread_null_sighandler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sigaction(s, &sa, NULL); + } + } + } + /* Test for cancellation */ + if (sigsetjmp(jmpbuf, 1) == 0) { + THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf); + if (! (THREAD_GETMEM(self, p_canceled) + && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) { + /* Reset the signal count */ + THREAD_SETMEM(self, p_signal, 0); + /* Say we're in sigwait */ + THREAD_SETMEM(self, p_sigwaiting, 1); + /* Unblock the signals and wait for them */ + sigsuspend(&mask); + } + } + THREAD_SETMEM(self, p_cancel_jmp, NULL); + /* The signals are now reblocked. Check for cancellation */ + pthread_testcancel(); + /* We should have self->p_signal != 0 and equal to the signal received */ + *sig = THREAD_GETMEM(self, p_signal); + return 0; +} + +/* Redefine raise() to send signal to calling thread only, + as per POSIX 1003.1c */ +int raise (int sig) +{ + int retcode = pthread_kill(pthread_self(), sig); + if (retcode == 0) + return 0; + else { + errno = retcode; + return -1; + } +} diff --git a/libpthread/linuxthreads.old/specific.c b/libpthread/linuxthreads.old/specific.c new file mode 100644 index 000000000..d8b5bb0b3 --- /dev/null +++ b/libpthread/linuxthreads.old/specific.c @@ -0,0 +1,204 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Thread-specific data */ + +#include +#define __USE_GNU +#include +#include +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" + + +/* Table of keys. */ + +static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = + { { 0, NULL } }; + +/* For debugging purposes put the maximum number of keys in a variable. */ +const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX; +const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE; + +/* Mutex to protect access to pthread_keys */ + +static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Create a new key */ + +int pthread_key_create(pthread_key_t * key, destr_function destr) +{ + int i; + + pthread_mutex_lock(&pthread_keys_mutex); + for (i = 0; i < PTHREAD_KEYS_MAX; i++) { + if (! pthread_keys[i].in_use) { + /* Mark key in use */ + pthread_keys[i].in_use = 1; + pthread_keys[i].destr = destr; + pthread_mutex_unlock(&pthread_keys_mutex); + *key = i; + return 0; + } + } + pthread_mutex_unlock(&pthread_keys_mutex); + return EAGAIN; +} + +/* Delete a key */ +int pthread_key_delete(pthread_key_t key) +{ + pthread_descr self = thread_self(); + + pthread_mutex_lock(&pthread_keys_mutex); + if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) { + pthread_mutex_unlock(&pthread_keys_mutex); + return EINVAL; + } + pthread_keys[key].in_use = 0; + pthread_keys[key].destr = NULL; + + /* Set the value of the key to NULL in all running threads, so + that if the key is reallocated later by pthread_key_create, its + associated values will be NULL in all threads. + Do nothing if no threads have been created yet. */ + if (__pthread_manager_request != -1) + { + pthread_descr th; + unsigned int idx1st, idx2nd; + + idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + th = self; + do { + /* If the thread already is terminated don't modify the memory. */ + if (!th->p_terminated && th->p_specific[idx1st] != NULL) + th->p_specific[idx1st][idx2nd] = NULL; + th = th->p_nextlive; + } while (th != self); + } + + pthread_mutex_unlock(&pthread_keys_mutex); + return 0; +} + +/* Set the value of a key */ + +int pthread_setspecific(pthread_key_t key, const void * pointer) +{ + pthread_descr self = thread_self(); + unsigned int idx1st, idx2nd; + + if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) + return EINVAL; + idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) { + void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *)); + if (newp == NULL) + return ENOMEM; + THREAD_SETMEM_NC(self, p_specific[idx1st], newp); + } + THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer; + return 0; +} + +/* Get the value of a key */ + +void * pthread_getspecific(pthread_key_t key) +{ + pthread_descr self = thread_self(); + unsigned int idx1st, idx2nd; + + if (key >= PTHREAD_KEYS_MAX) + return NULL; + idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; + idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; + if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL + || !pthread_keys[key].in_use) + return NULL; + return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd]; +} + +/* Call the destruction routines on all keys */ + +void __pthread_destroy_specifics() +{ + pthread_descr self = thread_self(); + int i, j, round, found_nonzero; + destr_function destr; + void * data; + + for (round = 0, found_nonzero = 1; + found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS; + round++) { + found_nonzero = 0; + for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) + if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) + for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) { + destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr; + data = THREAD_GETMEM_NC(self, p_specific[i])[j]; + if (destr != NULL && data != NULL) { + THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL; + destr(data); + found_nonzero = 1; + } + } + } + __pthread_lock(THREAD_GETMEM(self, p_lock), self); + for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) { + if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) { + free(THREAD_GETMEM_NC(self, p_specific[i])); + THREAD_SETMEM_NC(self, p_specific[i], NULL); + } + } + __pthread_unlock(THREAD_GETMEM(self, p_lock)); +} + + +/* Thread-specific data for libc. */ +#if !(USE_TLS && HAVE___THREAD) +static int +libc_internal_tsd_set(enum __libc_tsd_key_t key, const void * pointer) +{ + pthread_descr self = thread_self(); + + THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer); + return 0; +} +int (*__libc_internal_tsd_set)(enum __libc_tsd_key_t key, const void * pointer) + = libc_internal_tsd_set; + +static void * +libc_internal_tsd_get(enum __libc_tsd_key_t key) +{ + pthread_descr self = thread_self(); + + return THREAD_GETMEM_NC(self, p_libc_specific[key]); +} +void * (*__libc_internal_tsd_get)(enum __libc_tsd_key_t key) + = libc_internal_tsd_get; + +static void ** __attribute__ ((__const__)) +libc_internal_tsd_address (enum __libc_tsd_key_t key) +{ + pthread_descr self = thread_self(); + return &self->p_libc_specific[key]; +} +void **(*const __libc_internal_tsd_address) (enum __libc_tsd_key_t key) + __THROW __attribute__ ((__const__)) = libc_internal_tsd_address; +#endif diff --git a/libpthread/linuxthreads.old/spinlock.c b/libpthread/linuxthreads.old/spinlock.c new file mode 100644 index 000000000..cdf45f195 --- /dev/null +++ b/libpthread/linuxthreads.old/spinlock.c @@ -0,0 +1,723 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +/* Internal locks */ + +#define __FORCE_GLIBC +#include +#include +#include +#include +#include +#include +#include "pthread.h" +#include "internals.h" +#include "spinlock.h" +#include "restart.h" + +static void __pthread_acquire(int * spinlock); + +static inline void __pthread_release(int * spinlock) +{ + WRITE_MEMORY_BARRIER(); + *spinlock = __LT_SPINLOCK_INIT; + __asm __volatile ("" : "=m" (*spinlock) : "m" (*spinlock)); +} + + +/* The status field of a spinlock is a pointer whose least significant + bit is a locked flag. + + Thus the field values have the following meanings: + + status == 0: spinlock is free + status == 1: spinlock is taken; no thread is waiting on it + + (status & 1) == 1: spinlock is taken and (status & ~1L) is a + pointer to the first waiting thread; other + waiting threads are linked via the p_nextlock + field. + (status & 1) == 0: same as above, but spinlock is not taken. + + The waiting list is not sorted by priority order. + Actually, we always insert at top of list (sole insertion mode + that can be performed without locking). + For __pthread_unlock, we perform a linear search in the list + to find the highest-priority, oldest waiting thread. + This is safe because there are no concurrent __pthread_unlock + operations -- only the thread that locked the mutex can unlock it. */ + + +void internal_function __pthread_lock(struct _pthread_fastlock * lock, + pthread_descr self) +{ +#if defined HAS_COMPARE_AND_SWAP + long oldstatus, newstatus; + int successful_seizure, spurious_wakeup_count; + int spin_count; +#endif + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_acquire(&lock->__spinlock); + return; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + /* First try it without preparation. Maybe it's a completely + uncontested lock. */ + if (lock->__status == 0 && __compare_and_swap (&lock->__status, 0, 1)) + return; + + spurious_wakeup_count = 0; + spin_count = 0; + + /* On SMP, try spinning to get the lock. */ +#if 0 + if (__pthread_smp_kernel) { + int max_count = lock->__spinlock * 2 + 10; + + if (max_count > MAX_ADAPTIVE_SPIN_COUNT) + max_count = MAX_ADAPTIVE_SPIN_COUNT; + + for (spin_count = 0; spin_count < max_count; spin_count++) { + if (((oldstatus = lock->__status) & 1) == 0) { + if(__compare_and_swap(&lock->__status, oldstatus, oldstatus | 1)) + { + if (spin_count) + lock->__spinlock += (spin_count - lock->__spinlock) / 8; + READ_MEMORY_BARRIER(); + return; + } + } +#ifdef BUSY_WAIT_NOP + BUSY_WAIT_NOP; +#endif + __asm __volatile ("" : "=m" (lock->__status) : "m" (lock->__status)); + } + + lock->__spinlock += (spin_count - lock->__spinlock) / 8; + } +#endif + +again: + + /* No luck, try once more or suspend. */ + + do { + oldstatus = lock->__status; + successful_seizure = 0; + + if ((oldstatus & 1) == 0) { + newstatus = oldstatus | 1; + successful_seizure = 1; + } else { + if (self == NULL) + self = thread_self(); + newstatus = (long) self | 1; + } + + if (self != NULL) { + THREAD_SETMEM(self, p_nextlock, (pthread_descr) (oldstatus)); + /* Make sure the store in p_nextlock completes before performing + the compare-and-swap */ + MEMORY_BARRIER(); + } + } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); + + /* Suspend with guard against spurious wakeup. + This can happen in pthread_cond_timedwait_relative, when the thread + wakes up due to timeout and is still on the condvar queue, and then + locks the queue to remove itself. At that point it may still be on the + queue, and may be resumed by a condition signal. */ + + if (!successful_seizure) { + for (;;) { + suspend(self); + if (self->p_nextlock != NULL) { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + goto again; + } + + /* Put back any resumes we caught that don't belong to us. */ + while (spurious_wakeup_count--) + restart(self); + + READ_MEMORY_BARRIER(); +#endif +} + +int __pthread_unlock(struct _pthread_fastlock * lock) +{ +#if defined HAS_COMPARE_AND_SWAP + long oldstatus; + pthread_descr thr, * ptr, * maxptr; + int maxprio; +#endif + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_release(&lock->__spinlock); + return 0; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + WRITE_MEMORY_BARRIER(); + +again: + while ((oldstatus = lock->__status) == 1) { + if (__compare_and_swap_with_release_semantics(&lock->__status, + oldstatus, 0)) + return 0; + } + + /* Find thread in waiting queue with maximal priority */ + ptr = (pthread_descr *) &lock->__status; + thr = (pthread_descr) (oldstatus & ~1L); + maxprio = 0; + maxptr = ptr; + + /* Before we iterate over the wait queue, we need to execute + a read barrier, otherwise we may read stale contents of nodes that may + just have been inserted by other processors. One read barrier is enough to + ensure we have a stable list; we don't need one for each pointer chase + through the list, because we are the owner of the lock; other threads + can only add nodes at the front; if a front node is consistent, + the ones behind it must also be. */ + + READ_MEMORY_BARRIER(); + + while (thr != 0) { + if (thr->p_priority >= maxprio) { + maxptr = ptr; + maxprio = thr->p_priority; + } + ptr = &(thr->p_nextlock); + thr = (pthread_descr)((long)(thr->p_nextlock) & ~1L); + } + + /* Remove max prio thread from waiting list. */ + if (maxptr == (pthread_descr *) &lock->__status) { + /* If max prio thread is at head, remove it with compare-and-swap + to guard against concurrent lock operation. This removal + also has the side effect of marking the lock as released + because the new status comes from thr->p_nextlock whose + least significant bit is clear. */ + thr = (pthread_descr) (oldstatus & ~1L); + if (! __compare_and_swap_with_release_semantics + (&lock->__status, oldstatus, (long)(thr->p_nextlock) & ~1L)) + goto again; + } else { + /* No risk of concurrent access, remove max prio thread normally. + But in this case we must also flip the least significant bit + of the status to mark the lock as released. */ + thr = (pthread_descr)((long)*maxptr & ~1L); + *maxptr = thr->p_nextlock; + + /* Ensure deletion from linked list completes before we + release the lock. */ + WRITE_MEMORY_BARRIER(); + + do { + oldstatus = lock->__status; + } while (!__compare_and_swap_with_release_semantics(&lock->__status, + oldstatus, oldstatus & ~1L)); + } + + /* Wake up the selected waiting thread. Woken thread can check + its own p_nextlock field for NULL to detect that it has been removed. No + barrier is needed here, since restart() and suspend() take + care of memory synchronization. */ + + thr->p_nextlock = NULL; + restart(thr); + + return 0; +#endif +} + +/* + * Alternate fastlocks do not queue threads directly. Instead, they queue + * these wait queue node structures. When a timed wait wakes up due to + * a timeout, it can leave its wait node in the queue (because there + * is no safe way to remove from the quue). Some other thread will + * deallocate the abandoned node. + */ + + +struct wait_node { + struct wait_node *next; /* Next node in null terminated linked list */ + pthread_descr thr; /* The thread waiting with this node */ + int abandoned; /* Atomic flag */ +}; + +static long wait_node_free_list; +static int wait_node_free_list_spinlock; + +/* Allocate a new node from the head of the free list using an atomic + operation, or else using malloc if that list is empty. A fundamental + assumption here is that we can safely access wait_node_free_list->next. + That's because we never free nodes once we allocate them, so a pointer to a + node remains valid indefinitely. */ + +static struct wait_node *wait_node_alloc(void) +{ + struct wait_node *new_node = 0; + + __pthread_acquire(&wait_node_free_list_spinlock); + if (wait_node_free_list != 0) { + new_node = (struct wait_node *) wait_node_free_list; + wait_node_free_list = (long) new_node->next; + } + WRITE_MEMORY_BARRIER(); + __pthread_release(&wait_node_free_list_spinlock); + + if (new_node == 0) + return malloc(sizeof *wait_node_alloc()); + + return new_node; +} + +/* Return a node to the head of the free list using an atomic + operation. */ + +static void wait_node_free(struct wait_node *wn) +{ + __pthread_acquire(&wait_node_free_list_spinlock); + wn->next = (struct wait_node *) wait_node_free_list; + wait_node_free_list = (long) wn; + WRITE_MEMORY_BARRIER(); + __pthread_release(&wait_node_free_list_spinlock); + return; +} + +#if defined HAS_COMPARE_AND_SWAP + +/* Remove a wait node from the specified queue. It is assumed + that the removal takes place concurrently with only atomic insertions at the + head of the queue. */ + +static void wait_node_dequeue(struct wait_node **pp_head, + struct wait_node **pp_node, + struct wait_node *p_node) +{ + /* If the node is being deleted from the head of the + list, it must be deleted using atomic compare-and-swap. + Otherwise it can be deleted in the straightforward way. */ + + if (pp_node == pp_head) { + /* We don't need a read barrier between these next two loads, + because it is assumed that the caller has already ensured + the stability of *p_node with respect to p_node. */ + + long oldvalue = (long) p_node; + long newvalue = (long) p_node->next; + + if (__compare_and_swap((long *) pp_node, oldvalue, newvalue)) + return; + + /* Oops! Compare and swap failed, which means the node is + no longer first. We delete it using the ordinary method. But we don't + know the identity of the node which now holds the pointer to the node + being deleted, so we must search from the beginning. */ + + for (pp_node = pp_head; p_node != *pp_node; ) { + pp_node = &(*pp_node)->next; + READ_MEMORY_BARRIER(); /* Stabilize *pp_node for next iteration. */ + } + } + + *pp_node = p_node->next; + return; +} + +#endif + +void __pthread_alt_lock(struct _pthread_fastlock * lock, + pthread_descr self) +{ +#if defined HAS_COMPARE_AND_SWAP + long oldstatus, newstatus; +#endif + struct wait_node wait_node; + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + int suspend_needed = 0; + __pthread_acquire(&lock->__spinlock); + + if (lock->__status == 0) + lock->__status = 1; + else { + if (self == NULL) + self = thread_self(); + + wait_node.abandoned = 0; + wait_node.next = (struct wait_node *) lock->__status; + wait_node.thr = self; + lock->__status = (long) &wait_node; + suspend_needed = 1; + } + + __pthread_release(&lock->__spinlock); + + if (suspend_needed) + suspend (self); + return; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + do { + oldstatus = lock->__status; + if (oldstatus == 0) { + newstatus = 1; + } else { + if (self == NULL) + self = thread_self(); + wait_node.thr = self; + newstatus = (long) &wait_node; + } + wait_node.abandoned = 0; + wait_node.next = (struct wait_node *) oldstatus; + /* Make sure the store in wait_node.next completes before performing + the compare-and-swap */ + MEMORY_BARRIER(); + } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); + + /* Suspend. Note that unlike in __pthread_lock, we don't worry + here about spurious wakeup. That's because this lock is not + used in situations where that can happen; the restart can + only come from the previous lock owner. */ + + if (oldstatus != 0) + suspend(self); + + READ_MEMORY_BARRIER(); +#endif +} + +/* Timed-out lock operation; returns 0 to indicate timeout. */ + +int __pthread_alt_timedlock(struct _pthread_fastlock * lock, + pthread_descr self, const struct timespec *abstime) +{ + long oldstatus = 0; +#if defined HAS_COMPARE_AND_SWAP + long newstatus; +#endif + struct wait_node *p_wait_node = wait_node_alloc(); + + /* Out of memory, just give up and do ordinary lock. */ + if (p_wait_node == 0) { + __pthread_alt_lock(lock, self); + return 1; + } + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_acquire(&lock->__spinlock); + + if (lock->__status == 0) + lock->__status = 1; + else { + if (self == NULL) + self = thread_self(); + + p_wait_node->abandoned = 0; + p_wait_node->next = (struct wait_node *) lock->__status; + p_wait_node->thr = self; + lock->__status = (long) p_wait_node; + oldstatus = 1; /* force suspend */ + } + + __pthread_release(&lock->__spinlock); + goto suspend; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + do { + oldstatus = lock->__status; + if (oldstatus == 0) { + newstatus = 1; + } else { + if (self == NULL) + self = thread_self(); + p_wait_node->thr = self; + newstatus = (long) p_wait_node; + } + p_wait_node->abandoned = 0; + p_wait_node->next = (struct wait_node *) oldstatus; + /* Make sure the store in wait_node.next completes before performing + the compare-and-swap */ + MEMORY_BARRIER(); + } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); +#endif + +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + suspend: +#endif + + /* If we did not get the lock, do a timed suspend. If we wake up due + to a timeout, then there is a race; the old lock owner may try + to remove us from the queue. This race is resolved by us and the owner + doing an atomic testandset() to change the state of the wait node from 0 + to 1. If we succeed, then it's a timeout and we abandon the node in the + queue. If we fail, it means the owner gave us the lock. */ + + if (oldstatus != 0) { + if (timedsuspend(self, abstime) == 0) { + if (!testandset(&p_wait_node->abandoned)) + return 0; /* Timeout! */ + + /* Eat oustanding resume from owner, otherwise wait_node_free() below + will race with owner's wait_node_dequeue(). */ + suspend(self); + } + } + + wait_node_free(p_wait_node); + + READ_MEMORY_BARRIER(); + + return 1; /* Got the lock! */ +} + +void __pthread_alt_unlock(struct _pthread_fastlock *lock) +{ + struct wait_node *p_node, **pp_node, *p_max_prio, **pp_max_prio; + struct wait_node ** const pp_head = (struct wait_node **) &lock->__status; + int maxprio; + + WRITE_MEMORY_BARRIER(); + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_acquire(&lock->__spinlock); + } +#endif + + while (1) { + + /* If no threads are waiting for this lock, try to just + atomically release it. */ +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + if (lock->__status == 0 || lock->__status == 1) { + lock->__status = 0; + break; + } + } +#endif + +#if defined TEST_FOR_COMPARE_AND_SWAP + else +#endif + +#if defined HAS_COMPARE_AND_SWAP + { + long oldstatus = lock->__status; + if (oldstatus == 0 || oldstatus == 1) { + if (__compare_and_swap_with_release_semantics (&lock->__status, oldstatus, 0)) + break; + else + continue; + } + } +#endif + + /* Process the entire queue of wait nodes. Remove all abandoned + wait nodes and put them into the global free queue, and + remember the one unabandoned node which refers to the thread + having the highest priority. */ + + pp_max_prio = pp_node = pp_head; + p_max_prio = p_node = *pp_head; + maxprio = INT_MIN; + + READ_MEMORY_BARRIER(); /* Prevent access to stale data through p_node */ + + while (p_node != (struct wait_node *) 1) { + int prio; + + if (p_node->abandoned) { + /* Remove abandoned node. */ +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + *pp_node = p_node->next; +#endif +#if defined TEST_FOR_COMPARE_AND_SWAP + else +#endif +#if defined HAS_COMPARE_AND_SWAP + wait_node_dequeue(pp_head, pp_node, p_node); +#endif + wait_node_free(p_node); + /* Note that the next assignment may take us to the beginning + of the queue, to newly inserted nodes, if pp_node == pp_head. + In that case we need a memory barrier to stabilize the first of + these new nodes. */ + p_node = *pp_node; + if (pp_node == pp_head) + READ_MEMORY_BARRIER(); /* No stale reads through p_node */ + continue; + } else if ((prio = p_node->thr->p_priority) >= maxprio) { + /* Otherwise remember it if its thread has a higher or equal priority + compared to that of any node seen thus far. */ + maxprio = prio; + pp_max_prio = pp_node; + p_max_prio = p_node; + } + + /* This canno6 jump backward in the list, so no further read + barrier is needed. */ + pp_node = &p_node->next; + p_node = *pp_node; + } + + /* If all threads abandoned, go back to top */ + if (maxprio == INT_MIN) + continue; + + ASSERT (p_max_prio != (struct wait_node *) 1); + + /* Now we want to to remove the max priority thread's wait node from + the list. Before we can do this, we must atomically try to change the + node's abandon state from zero to nonzero. If we succeed, that means we + have the node that we will wake up. If we failed, then it means the + thread timed out and abandoned the node in which case we repeat the + whole unlock operation. */ + + if (!testandset(&p_max_prio->abandoned)) { +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + *pp_max_prio = p_max_prio->next; +#endif +#if defined TEST_FOR_COMPARE_AND_SWAP + else +#endif +#if defined HAS_COMPARE_AND_SWAP + wait_node_dequeue(pp_head, pp_max_prio, p_max_prio); +#endif + restart(p_max_prio->thr); + break; + } + } + +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + __pthread_release(&lock->__spinlock); + } +#endif +} + + +/* Compare-and-swap emulation with a spinlock */ + +#ifdef TEST_FOR_COMPARE_AND_SWAP +int __pthread_has_cas = 0; +#endif + +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + +int __pthread_compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock) +{ + int res; + + __pthread_acquire(spinlock); + + if (*ptr == oldval) { + *ptr = newval; res = 1; + } else { + res = 0; + } + + __pthread_release(spinlock); + + return res; +} + +#endif + +/* The retry strategy is as follows: + - We test and set the spinlock MAX_SPIN_COUNT times, calling + sched_yield() each time. This gives ample opportunity for other + threads with priority >= our priority to make progress and + release the spinlock. + - If a thread with priority < our priority owns the spinlock, + calling sched_yield() repeatedly is useless, since we're preventing + the owning thread from making progress and releasing the spinlock. + So, after MAX_SPIN_LOCK attemps, we suspend the calling thread + using nanosleep(). This again should give time to the owning thread + for releasing the spinlock. + Notice that the nanosleep() interval must not be too small, + since the kernel does busy-waiting for short intervals in a realtime + process (!). The smallest duration that guarantees thread + suspension is currently 2ms. + - When nanosleep() returns, we try again, doing MAX_SPIN_COUNT + sched_yield(), then sleeping again if needed. */ + +static void __pthread_acquire(int * spinlock) +{ + int cnt = 0; + struct timespec tm; + + READ_MEMORY_BARRIER(); + + while (testandset(spinlock)) { + if (cnt < MAX_SPIN_COUNT) { + sched_yield(); + cnt++; + } else { + tm.tv_sec = 0; + tm.tv_nsec = SPIN_SLEEP_DURATION; + nanosleep(&tm, NULL); + cnt = 0; + } + } +} diff --git a/libpthread/linuxthreads.old/spinlock.h b/libpthread/linuxthreads.old/spinlock.h new file mode 100644 index 000000000..0ec40c57c --- /dev/null +++ b/libpthread/linuxthreads.old/spinlock.h @@ -0,0 +1,218 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#include + + +/* There are 2 compare and swap synchronization primitives with + different semantics: + + 1. compare_and_swap, which has acquire semantics (i.e. it + completes befor subsequent writes.) + 2. compare_and_swap_with_release_semantics, which has release + semantics (it completes after previous writes.) + + For those platforms on which they are the same. HAS_COMPARE_AND_SWAP + should be defined. For those platforms on which they are different, + HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS has to be defined. */ + +#ifndef HAS_COMPARE_AND_SWAP +#ifdef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS +#define HAS_COMPARE_AND_SWAP +#endif +#endif + +#if defined(TEST_FOR_COMPARE_AND_SWAP) + +extern int __pthread_has_cas; +extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock); + +static inline int compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock) +{ + if (__builtin_expect (__pthread_has_cas, 1)) + return __compare_and_swap(ptr, oldval, newval); + else + return __pthread_compare_and_swap(ptr, oldval, newval, spinlock); +} + +#elif defined(HAS_COMPARE_AND_SWAP) + +#ifdef IMPLEMENT_TAS_WITH_CAS +#define testandset(p) !__compare_and_swap((long int *) p, 0, 1) +#endif + +#ifdef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS + +static inline int +compare_and_swap_with_release_semantics (long * ptr, long oldval, + long newval, int * spinlock) +{ + return __compare_and_swap_with_release_semantics (ptr, oldval, + newval); +} + +#endif + +static inline int compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock) +{ + return __compare_and_swap(ptr, oldval, newval); +} + +#else + +extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock); + +static inline int compare_and_swap(long * ptr, long oldval, long newval, + int * spinlock) +{ + return __pthread_compare_and_swap(ptr, oldval, newval, spinlock); +} + +#endif + +#ifndef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS +#define compare_and_swap_with_release_semantics compare_and_swap +#define __compare_and_swap_with_release_semantics __compare_and_swap +#endif + +/* Internal locks */ + +extern void internal_function __pthread_lock(struct _pthread_fastlock * lock, + pthread_descr self); +extern int __pthread_unlock(struct _pthread_fastlock *lock); + +static inline void __pthread_init_lock(struct _pthread_fastlock * lock) +{ + lock->__status = 0; + lock->__spinlock = __LT_SPINLOCK_INIT; +} + +static inline int __pthread_trylock (struct _pthread_fastlock * lock) +{ +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + return (testandset(&lock->__spinlock) ? EBUSY : 0); + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + do { + if (lock->__status != 0) return EBUSY; + } while(! __compare_and_swap(&lock->__status, 0, 1)); + return 0; +#endif +} + +/* Variation of internal lock used for pthread_mutex_t, supporting + timed-out waits. Warning: do not mix these operations with the above ones + over the same lock object! */ + +extern void __pthread_alt_lock(struct _pthread_fastlock * lock, + pthread_descr self); + +extern int __pthread_alt_timedlock(struct _pthread_fastlock * lock, + pthread_descr self, const struct timespec *abstime); + +extern void __pthread_alt_unlock(struct _pthread_fastlock *lock); + +static inline void __pthread_alt_init_lock(struct _pthread_fastlock * lock) +{ + lock->__status = 0; + lock->__spinlock = __LT_SPINLOCK_INIT; +} + +static inline int __pthread_alt_trylock (struct _pthread_fastlock * lock) +{ +#if defined TEST_FOR_COMPARE_AND_SWAP + if (!__pthread_has_cas) +#endif +#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP + { + int res = EBUSY; + + if (testandset(&lock->__spinlock) == 0) + { + if (lock->__status == 0) + { + lock->__status = 1; + WRITE_MEMORY_BARRIER(); + res = 0; + } + lock->__spinlock = __LT_SPINLOCK_INIT; + } + return res; + } +#endif + +#if defined HAS_COMPARE_AND_SWAP + do { + if (lock->__status != 0) return EBUSY; + } while(! compare_and_swap(&lock->__status, 0, 1, &lock->__spinlock)); + return 0; +#endif +} + +/* Operations on pthread_atomic, which is defined in internals.h */ + +static inline long atomic_increment(struct pthread_atomic *pa) +{ + long oldval; + + do { + oldval = pa->p_count; + } while (!compare_and_swap(&pa->p_count, oldval, oldval + 1, &pa->p_spinlock)); + + return oldval; +} + + +static inline long atomic_decrement(struct pthread_atomic *pa) +{ + long oldval; + + do { + oldval = pa->p_count; + } while (!compare_and_swap(&pa->p_count, oldval, oldval - 1, &pa->p_spinlock)); + + return oldval; +} + + +static inline void +__pthread_set_own_extricate_if (pthread_descr self, pthread_extricate_if *peif) +{ + /* Only store a non-null peif if the thread has cancellation enabled. + Otherwise pthread_cancel will unconditionally call the extricate handler, + and restart the thread giving rise to forbidden spurious wakeups. */ + if (peif == NULL + || THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) + { + /* If we are removing the extricate interface, we need to synchronize + against pthread_cancel so that it does not continue with a pointer + to a deallocated pthread_extricate_if struct! The thread lock + is (ab)used for this synchronization purpose. */ + if (peif == NULL) + __pthread_lock (THREAD_GETMEM(self, p_lock), self); + THREAD_SETMEM(self, p_extricate, peif); + if (peif == NULL) + __pthread_unlock (THREAD_GETMEM(self, p_lock)); + } +} diff --git a/libpthread/linuxthreads.old/sysdeps/alpha/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/alpha/pt-machine.h new file mode 100644 index 000000000..853ac6f04 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/alpha/pt-machine.h @@ -0,0 +1,128 @@ +/* Machine-dependent pthreads configuration and inline functions. + Alpha version. + Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +#ifdef __linux__ +# include +#else +# include +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char *stack_pointer __asm__("$30"); + + +/* Memory barrier; default is to do nothing */ +#define MEMORY_BARRIER() __asm__ __volatile__("mb" : : : "memory") +/* Write barrier. */ +#define WRITE_MEMORY_BARRIER() __asm__ __volatile__("wmb" : : : "memory") + + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret, temp; + + __asm__ __volatile__( + "/* Inline spinlock test & set */\n" + "1:\t" + "ldl_l %0,%3\n\t" + "bne %0,2f\n\t" + "or $31,1,%1\n\t" + "stl_c %1,%2\n\t" + "beq %1,1b\n" + "2:\tmb\n" + "/* End spinlock test & set */" + : "=&r"(ret), "=&r"(temp), "=m"(*spinlock) + : "m"(*spinlock) + : "memory"); + + return ret; +} + + +/* Begin allocating thread stacks at this address. Default is to allocate + them just below the initial program stack. */ +#define THREAD_STACK_START_ADDRESS 0x40000000000 + + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF \ +({ \ + register pthread_descr __self __asm__("$0"); \ + __asm__ ("call_pal %1" : "=r"(__self) : "i"(PAL_rduniq)); \ + __self; \ +}) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) \ +{ \ + register pthread_descr __self __asm__("$16") = (descr); \ + __asm__ __volatile__ ("call_pal %1" : : "r"(__self), "i"(PAL_wruniq)); \ +} + + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + long int ret; + + __asm__ __volatile__ ( + "/* Inline compare & swap */\n" + "1:\t" + "ldq_l %0,%4\n\t" + "cmpeq %0,%2,%0\n\t" + "beq %0,2f\n\t" + "mov %3,%0\n\t" + "stq_c %0,%1\n\t" + "beq %0,1b\n\t" + "2:\tmb\n" + "/* End compare & swap */" + : "=&r"(ret), "=m"(*p) + : "r"(oldval), "r"(newval), "m"(*p) + : "memory"); + + return ret; +} + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h new file mode 100644 index 000000000..284567970 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/arm/pt-machine.h @@ -0,0 +1,70 @@ +/* Machine-dependent pthreads configuration and inline functions. + ARM version. + Copyright (C) 1997, 1998, 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Philip Blundell . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* This will not work on ARM1 or ARM2 because SWP is lacking on those + machines. Unfortunately we have no way to detect this at compile + time; let's hope nobody tries to use one. */ + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + register unsigned int ret; + +#if defined(__thumb__) + void *pc; + __asm__ __volatile__( + ".align 0\n" + "\tbx pc\n" + "\tnop\n" + "\t.arm\n" + "\tswp %0, %2, [%3]\n" + "\torr %1, pc, #1\n" + "\tbx %1\n" + "\t.force_thumb" + : "=r"(ret), "=r"(pc) + : "0"(1), "r"(spinlock)); +#else + __asm__ __volatile__("swp %0, %1, [%2]" + : "=r"(ret) + : "0"(1), "r"(spinlock)); +#endif + + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("sp"); + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/bfin/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/bfin/pt-machine.h new file mode 100644 index 000000000..fef16263e --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/bfin/pt-machine.h @@ -0,0 +1,57 @@ +/* Machine-dependent pthreads configuration and inline functions. + Copyright (C) 1996, 1998, 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long *, long , long); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + if (*spinlock) + return 1; + else + { + *spinlock=1; + return 0; + } +} + +#define HAS_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + if((*p ^ oldval) == 0) { + *p = newval; + return 1; + } + else + return 0; +} + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/cris/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/cris/pt-machine.h new file mode 100644 index 000000000..431da7101 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/cris/pt-machine.h @@ -0,0 +1,58 @@ +/* Machine-dependent pthreads configuration and inline functions. + CRIS version. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +PT_EI long int +testandset (int *spinlock) +{ + register unsigned long int ret; + + /* Note the use of a dummy output of *spinlock to expose the write. The + memory barrier is to stop *other* writes being moved past this code. */ + __asm__ __volatile__("clearf\n" + "0:\n\t" + "movu.b [%2],%0\n\t" + "ax\n\t" + "move.b %3,[%2]\n\t" + "bwf 0b\n\t" + "clearf" + : "=&r" (ret), "=m" (*spinlock) + : "r" (spinlock), "r" ((int) 1) + : "memory"); + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. + I don't trust register variables, so let's do this the safe way. */ +#define CURRENT_STACK_FRAME \ + ({ char *sp; __asm__ ("move.d $sp,%0" : "=rm" (sp)); sp; }) + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/frv/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/frv/pt-machine.h new file mode 100644 index 000000000..64df5ffdb --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/frv/pt-machine.h @@ -0,0 +1,68 @@ +/* Machine-dependent pthreads configuration and inline functions. + FR-V version. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Alexandre Oliva + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef __ASSEMBLER__ + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int i = 1; + asm ("swap%I0 %M0, %1" : "+m"(*(volatile int *)spinlock), "+r"(i)); + return i; +} + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* This symbol is defined by the ABI as the stack size requested by + the main program. */ +extern char __stacksize; +#define ARCH_STACK_MAX_SIZE ((unsigned long)&__stacksize) + +/* Memory barrier; default is to do nothing */ +#define MEMORY_BARRIER() __asm__ __volatile__("membar" : : : "memory") +/* Write barrier. */ +#define WRITE_MEMORY_BARRIER() __asm__ __volatile__("membar" : : : "memory") + +/* Return the thread descriptor for the current thread. */ +register struct _pthread_descr_struct *THREAD_SELF asm ("gr29"); +#define THREAD_SELF THREAD_SELF + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) \ + (THREAD_SELF = descr) + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("sp"); + +#endif + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/i386/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/i386/pt-machine.h new file mode 100644 index 000000000..af1818d7b --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/i386/pt-machine.h @@ -0,0 +1,158 @@ +/* Machine-dependent pthreads configuration and inline functions. + i386 version. + Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef __ASSEMBLER__ +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME __builtin_frame_address (0) + + +/* See if we can optimize for newer cpus... */ +#if defined __GNUC__ && __GNUC__ >= 2 && \ + (defined __i486__ || defined __pentium__ || defined __pentiumpro__ || defined __pentium4__ || \ + defined __athlon__ || defined __k8__) + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret; + + __asm__ __volatile__ ( + "xchgl %0, %1" + : "=r" (ret), "=m" (*spinlock) + : "0" (1), "m" (*spinlock) + : "memory"); + + return ret; +} + +/* Compare-and-swap for semaphores. It's always available on i686. */ +#define HAS_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (newval), "m" (*p), "a" (oldval) + : "memory"); + return ret; +} + +#if __ASSUME_LDT_WORKS > 0 +#include "../useldt.h" +#endif + +/* The P4 and above really want some help to prevent overheating. */ +#define BUSY_WAIT_NOP __asm__ ("rep; nop") + + +#else /* Generic i386 implementation */ + + + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret; + + __asm__ __volatile__( + "xchgl %0, %1" + : "=r"(ret), "=m"(*spinlock) + : "0"(1), "m"(*spinlock) + : "memory"); + + return ret; +} + + +/* Compare-and-swap for semaphores. + Available on the 486 and above, but not on the 386. + We test dynamically whether it's available or not. */ + +#define HAS_COMPARE_AND_SWAP +#define TEST_FOR_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (newval), "m" (*p), "a" (oldval) + : "memory"); + return ret; +} + + +PT_EI int +get_eflags (void) +{ + int res; + __asm__ __volatile__ ("pushfl; popl %0" : "=r" (res) : ); + return res; +} + + +PT_EI void +set_eflags (int newflags) +{ + __asm__ __volatile__ ("pushl %0; popfl" : : "r" (newflags) : "cc"); +} + + +PT_EI int +compare_and_swap_is_available (void) +{ + int oldflags = get_eflags (); + int changed; + /* Flip AC bit in EFLAGS. */ + set_eflags (oldflags ^ 0x40000); + /* See if bit changed. */ + changed = (get_eflags () ^ oldflags) & 0x40000; + /* Restore EFLAGS. */ + set_eflags (oldflags); + /* If the AC flag did not change, it's a 386 and it lacks cmpxchg. + Otherwise, it's a 486 or above and it has cmpxchg. */ + return changed != 0; +} +#endif /* Generic i386 implementation */ + +#endif /* __ASSEMBLER__ */ + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/i386/tls.h b/libpthread/linuxthreads.old/sysdeps/i386/tls.h new file mode 100644 index 000000000..e4f007ee3 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/i386/tls.h @@ -0,0 +1,185 @@ +/* Definition for thread-local data handling. linuxthreads/i386 version. + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +# include + +#ifndef __ASSEMBLER__ +# include +# include +# include + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ +} tcbhead_t; +#endif + + +/* We can support TLS only if the floating-stack support is available. */ +#if defined FLOATING_STACKS && defined HAVE_TLS_SUPPORT + +/* Signal that TLS support is available. */ +//# define USE_TLS 1 + +# ifndef __ASSEMBLER__ +/* Get system call information. */ +# include + + +/* Get the thread descriptor definition. */ +# include + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +# ifdef __PIC__ +# define TLS_EBX_ARG "r" +# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t" +# else +# define TLS_EBX_ARG "b" +# define TLS_LOAD_EBX +# endif + +# define TLS_DO_MODIFY_LDT(descr, nr) \ +({ \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + int result; \ + asm volatile (TLS_LOAD_EBX \ + "int $0x80\n\t" \ + TLS_LOAD_EBX \ + : "=a" (result) \ + : "0" (__NR_modify_ldt), \ + /* The extra argument with the "m" constraint is necessary \ + to let the compiler know that we are accessing LDT_ENTRY \ + here. */ \ + "m" (ldt_entry), TLS_EBX_ARG (1), "c" (&ldt_entry), \ + "d" (sizeof (ldt_entry))); \ + __builtin_expect (result, 0) != 0 ? -1 : nr * 8 + 7; \ +}) + +# define TLS_DO_SET_THREAD_AREA(descr, secondcall) \ +({ \ + struct modify_ldt_ldt_s ldt_entry = \ + { -1, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + int result; \ + if (secondcall) \ + ldt_entry.entry_number = ({ int _gs; \ + asm ("movw %%gs, %w0" : "=q" (_gs)); \ + (_gs & 0xffff) >> 3; }); \ + asm volatile (TLS_LOAD_EBX \ + "int $0x80\n\t" \ + TLS_LOAD_EBX \ + : "=a" (result), "=m" (ldt_entry.entry_number) \ + : "0" (__NR_set_thread_area), \ + /* The extra argument with the "m" constraint is necessary \ + to let the compiler know that we are accessing LDT_ENTRY \ + here. */ \ + TLS_EBX_ARG (&ldt_entry), "m" (ldt_entry)); \ + __builtin_expect (result, 0) == 0 ? ldt_entry.entry_number * 8 + 3 : -1; \ +}) + +# ifdef __ASSUME_SET_THREAD_AREA_SYSCALL +# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ + TLS_DO_SET_THREAD_AREA (descr, firstcall) +# elif defined __NR_set_thread_area +# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ + ({ int __seg = TLS_DO_SET_THREAD_AREA (descr, secondcall); \ + __seg == -1 ? TLS_DO_MODIFY_LDT (descr, 0) : __seg; }) +# else +# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ + TLS_DO_MODIFY_LDT ((descr), 0) +# endif + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(descr, secondcall) \ + ({ \ + void *_descr = (descr); \ + tcbhead_t *head = _descr; \ + int __gs; \ + \ + head->tcb = _descr; \ + /* For now the thread descriptor is at the same address. */ \ + head->self = _descr; \ + \ + __gs = TLS_SETUP_GS_SEGMENT (_descr, secondcall); \ + if (__builtin_expect (__gs, 7) != -1) \ + { \ + asm ("movw %w0, %%gs" : : "q" (__gs)); \ + __gs = 0; \ + } \ + __gs; \ + }) + + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_GETMEM (__descr, p_header.data.dtvp); }) + +# endif /* FLOATING_STACKS && HAVE_TLS_SUPPORT */ +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/i386/useldt.h b/libpthread/linuxthreads.old/sysdeps/i386/useldt.h new file mode 100644 index 000000000..16aee9989 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/i386/useldt.h @@ -0,0 +1,307 @@ +/* Special definitions for ix86 machine using segment register based + thread descriptor. + Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef __ASSEMBLER__ +#include /* For offsetof. */ +#include /* For abort(). */ + + +/* We don't want to include the kernel header. So duplicate the + information. */ + +/* Structure passed on `modify_ldt' call. */ +struct modify_ldt_ldt_s +{ + unsigned int entry_number; + unsigned long int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int empty:25; +}; + +/* System call to set LDT entry. */ +extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t); + + +/* Return the thread descriptor for the current thread. + + The contained asm must *not* be marked volatile since otherwise + assignments like + pthread_descr self = thread_self(); + do not get optimized away. */ +#define THREAD_SELF \ +({ \ + register pthread_descr __self; \ + __asm__ ("movl %%gs:%c1,%0" : "=r" (__self) \ + : "i" (offsetof (struct _pthread_descr_struct, \ + p_header.data.self))); \ + __self; \ +}) + + +/* Initialize the thread-unique value. Two possible ways to do it. */ + +#define DO_MODIFY_LDT(descr, nr) \ +({ \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) \ + abort (); \ + asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7)); \ +}) + +#ifdef __PIC__ +# define USETLS_EBX_ARG "r" +# define USETLS_LOAD_EBX "xchgl %3, %%ebx\n\t" +#else +# define USETLS_EBX_ARG "b" +# define USETLS_LOAD_EBX +#endif + +/* When using the new set_thread_area call, we don't need to change %gs + because we inherited the value set up in the main thread by TLS setup. + We need to extract that value and set up the same segment in this + thread. */ +#if USE_TLS +# define DO_SET_THREAD_AREA_REUSE(nr) 1 +#else +/* Without TLS, we do the initialization of the main thread, where NR == 0. */ +# define DO_SET_THREAD_AREA_REUSE(nr) (!__builtin_constant_p (nr) || (nr)) +#endif +#define DO_SET_THREAD_AREA(descr, nr) \ +({ \ + int __gs; \ + if (DO_SET_THREAD_AREA_REUSE (nr)) \ + { \ + asm ("movw %%gs, %w0" : "=q" (__gs)); \ + struct modify_ldt_ldt_s ldt_entry = \ + { (__gs & 0xffff) >> 3, \ + (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + \ + int __result; \ + __asm (USETLS_LOAD_EBX \ + "movl %2, %%eax\n\t" \ + "int $0x80\n\t" \ + USETLS_LOAD_EBX \ + : "&a" (__result) \ + : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area)); \ + if (__result == 0) \ + asm ("movw %w0, %%gs" :: "q" (__gs)); \ + else \ + __gs = -1; \ + } \ + else \ + { \ + struct modify_ldt_ldt_s ldt_entry = \ + { -1, \ + (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ + 1, 0, 0, 1, 0, 1, 0 }; \ + int __result; \ + __asm (USETLS_LOAD_EBX \ + "movl %2, %%eax\n\t" \ + "int $0x80\n\t" \ + USETLS_LOAD_EBX \ + : "&a" (__result) \ + : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area)); \ + if (__result == 0) \ + { \ + __gs = (ldt_entry.entry_number << 3) + 3; \ + asm ("movw %w0, %%gs" : : "q" (__gs)); \ + } \ + else \ + __gs = -1; \ + } \ + __gs; \ +}) + +#if defined __ASSUME_SET_THREAD_AREA_SYSCALL +# define INIT_THREAD_SELF(descr, nr) DO_SET_THREAD_AREA (descr, nr) +#elif defined __NR_set_thread_area +# define INIT_THREAD_SELF(descr, nr) \ +({ \ + if (__builtin_expect (__have_no_set_thread_area, 0) \ + || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1 \ + && (__have_no_set_thread_area = 1))) \ + DO_MODIFY_LDT (descr, nr); \ +}) +/* Defined in pspinlock.c. */ +extern int __have_no_set_thread_area; +#else +# define INIT_THREAD_SELF(descr, nr) DO_MODIFY_LDT (descr, nr) +#endif + +/* Free resources associated with thread descriptor. */ +#ifdef __ASSUME_SET_THREAD_AREA_SYSCALL +#define FREE_THREAD(descr, nr) do { } while (0) +#elif defined __NR_set_thread_area +#define FREE_THREAD(descr, nr) \ +{ \ + int __gs; \ + __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs)); \ + if (__builtin_expect (__gs & 4, 0)) \ + { \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \ + __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \ + } \ +} +#else +#define FREE_THREAD(descr, nr) \ +{ \ + struct modify_ldt_ldt_s ldt_entry = \ + { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \ + __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \ +} +#endif + +/* Read member of the thread descriptor directly. */ +#define THREAD_GETMEM(descr, member) \ +({ \ + __typeof__ (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %%gs:%P2,%b0" \ + : "=q" (__value) \ + : "0" (0), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %%gs:%P1,%0" \ + : "=r" (__value) \ + : "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, 4 or 8. */\ + abort (); \ + \ + __asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t" \ + "movl %%gs:%P2,%%edx" \ + : "=A" (__value) \ + : "i" (offsetof (struct _pthread_descr_struct, \ + member)), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member) + 4)); \ + } \ + __value; \ +}) + +/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ +#define THREAD_GETMEM_NC(descr, member) \ +({ \ + __typeof__ (descr->member) __value; \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %%gs:(%2),%b0" \ + : "=q" (__value) \ + : "0" (0), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %%gs:(%1),%0" \ + : "=r" (__value) \ + : "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, 4 or 8. */\ + abort (); \ + \ + __asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t" \ + "movl %%gs:4(%1),%%edx" \ + : "=&A" (__value) \ + : "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ + __value; \ +}) + +/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ +#define THREAD_SETMEM(descr, member, value) \ +({ \ + __typeof__ (descr->member) __value = (value); \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %0,%%gs:%P1" : \ + : "q" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %0,%%gs:%P1" : \ + : "r" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, 4 or 8. */\ + abort (); \ + \ + __asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n" \ + "movl %%edx,%%gs:%P2" : \ + : "A" (__value), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member)), \ + "i" (offsetof (struct _pthread_descr_struct, \ + member) + 4)); \ + } \ +}) + +/* Set member of the thread descriptor directly. */ +#define THREAD_SETMEM_NC(descr, member, value) \ +({ \ + __typeof__ (descr->member) __value = (value); \ + if (sizeof (__value) == 1) \ + __asm__ __volatile__ ("movb %0,%%gs:(%1)" : \ + : "q" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else if (sizeof (__value) == 4) \ + __asm__ __volatile__ ("movl %0,%%gs:(%1)" : \ + : "r" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + else \ + { \ + if (sizeof (__value) != 8) \ + /* There should not be any value with a size other than 1, 4 or 8. */\ + abort (); \ + \ + __asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t" \ + "movl %%edx,%%gs:4(%1)" : \ + : "A" (__value), \ + "r" (offsetof (struct _pthread_descr_struct, \ + member))); \ + } \ +}) +#endif + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 8*1024*1024 diff --git a/libpthread/linuxthreads.old/sysdeps/m68k/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/m68k/pt-machine.h new file mode 100644 index 000000000..4670ae3c4 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/m68k/pt-machine.h @@ -0,0 +1,76 @@ +/* Machine-dependent pthreads configuration and inline functions. + m68k version. + Copyright (C) 1996, 1998, 2000, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + char ret; + + __asm__ __volatile__( +#if !defined(__mcoldfire__) && !defined(__mcf5200__) && !defined(__m68000) + "tas %1; sne %0" +#else + "bset #7,%1; sne %0" +#endif + : "=dm"(ret), "=m"(*spinlock) + : "m"(*spinlock) + : "cc"); + + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("%sp"); + + +/* Compare-and-swap for semaphores. */ + +#if !defined(__mcoldfire__) && !defined(__mcf5200__) && !defined(__mc68000) +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("casl %2, %3, %1; seq %0" + : "=dm" (ret), "=m" (*p), "=d" (readval) + : "d" (newval), "m" (*p), "2" (oldval)); + + return ret; +} +#endif + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/mips/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/mips/pt-machine.h new file mode 100644 index 000000000..f7efc881d --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/mips/pt-machine.h @@ -0,0 +1,110 @@ +/* Machine-dependent pthreads configuration and inline functions. + + Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ralf Baechle . + Based on the Alpha version by Richard Henderson . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#include + +/* Copyright (C) 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Maciej W. Rozycki , 2000. */ +static inline int +_test_and_set (int *p, int v) __THROW +{ + int r, t; + + __asm__ __volatile__ + ("/* Inline test and set */\n" + "1:\n\t" + ".set push\n\t" + ".set mips2\n\t" + "ll %0,%3\n\t" + "move %1,%4\n\t" + "beq %0,%4,2f\n\t" + "sc %1,%2\n\t" + ".set pop\n\t" + "beqz %1,1b\n" + "2:\n\t" + "/* End test and set */" + : "=&r" (r), "=&r" (t), "=m" (*p) + : "m" (*p), "r" (v) + : "memory"); + + return r; +} + + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + + +/* Spinlock implementation; required. */ + +PT_EI long int +testandset (int *spinlock) +{ + return _test_and_set (spinlock, 1); +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("$29"); + + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + long int ret, temp; + + __asm__ __volatile__ + ("/* Inline compare & swap */\n" + "1:\n\t" + ".set push\n\t" + ".set mips2\n\t" + "ll %1,%5\n\t" + "move %0,$0\n\t" + "bne %1,%3,2f\n\t" + "move %0,%4\n\t" + "sc %0,%2\n\t" + ".set pop\n\t" + "beqz %0,1b\n" + "2:\n\t" + "/* End compare & swap */" + : "=&r" (ret), "=&r" (temp), "=m" (*p) + : "r" (oldval), "r" (newval), "m" (*p) + : "memory"); + + return ret; +} + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/nios/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/nios/pt-machine.h new file mode 100644 index 000000000..5d82b8d16 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/nios/pt-machine.h @@ -0,0 +1,67 @@ +/* Machine-dependent pthreads configuration and inline functions. + ARM version. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Philip Blundell . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline +#endif + +extern long int testandset (int *spinlock); +/* Spinlock implementation; required. */ +/* it is weird and dangerous to disable interrupt in userspace, but for nios + what else we can do before we have a swap like instruction? This is better + than nothing + */ +PT_EI long int +testandset (int *spinlock) +{ + unsigned int ret; + + __asm__ __volatile__("pfx 8\n\t" + "wrctl %1 ; disable interrupt\n\t" + "nop\n\t" + "nop\n\t" + "ld %0, [%2]\n\t" + "st [%2], %1\n\t" + "pfx 9\n\t" + "wrctl %1 ; enable interrupt\n\t" + "nop\n\t" + "nop\n\t" + : "=&r"(ret) + : "r"(1), "r"(spinlock) + : "memory"); + + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("%sp"); + +/* nios needs more because of reg windows */ +#define THREAD_MANAGER_STACK_SIZE (32*1024) +#define STACK_SIZE (32*1024) + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/nios2/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/nios2/pt-machine.h new file mode 100644 index 000000000..484a77e14 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/nios2/pt-machine.h @@ -0,0 +1,58 @@ +/* Machine-dependent pthreads configuration and inline functions. + nios2 version. + Copyright (C) 1996, 1998, 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline +#endif + +extern long int testandset (int *spinlock); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + unsigned int scratch; + long int ret=-2; + + __asm__ __volatile__( + "rdctl %0, status\n\t" + "and %0, %0, %1\n\t" + "wrctl status, %0 #disable interrupts\n\t" + "ldw %1, 0(%4)\n\t" + "stw %3, 0(%4)\n\t" + "ori %0, %0, 1\n\t" + "wrctl status, %0 #enable interrupts\n\t" + : "=&r"(scratch), "=r"(ret) + : "1"(ret), "r"(1), "r"(spinlock) + : "memory"); + + return ret; +} + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("%sp"); + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/powerpc/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/powerpc/pt-machine.h new file mode 100644 index 000000000..9e6543a26 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/powerpc/pt-machine.h @@ -0,0 +1,103 @@ +/* Machine-dependent pthreads configuration and inline functions. + powerpc version. + Copyright (C) 1996, 1997, 1998, 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* These routines are from Appendix G of the 'PowerPC 601 RISC Microprocessor + User's Manual', by IBM and Motorola. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* For multiprocessor systems, we want to ensure all memory accesses + are completed before we reset a lock. On other systems, we still + need to make sure that the compiler has flushed everything to memory. */ +#define MEMORY_BARRIER() __asm__ __volatile__ ("sync" : : : "memory") + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("r1"); + +/* Register r2 (tp) is reserved by the ABI as "thread pointer". */ +struct _pthread_descr_struct; +register struct _pthread_descr_struct *__thread_self __asm__("r2"); + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) + +/* Compare-and-swap for semaphores. */ +/* note that test-and-set(x) is the same as !compare-and-swap(x, 0, 1) */ + +#define HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS +#define IMPLEMENT_TAS_WITH_CAS + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + int ret; + + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r"(newval), "r"(oldval) + : "cr0", "memory"); + /* This version of __compare_and_swap is to be used when acquiring + a lock, so we don't need to worry about whether other memory + operations have completed, but we do need to be sure that any loads + after this point really occur after we have acquired the lock. */ + __asm__ __volatile__ ("isync" : : : "memory"); + return ret == 0; +} + +PT_EI int +__compare_and_swap_with_release_semantics (long int *p, + long int oldval, long int newval) +{ + int ret; + + MEMORY_BARRIER (); + __asm__ __volatile__ ( + "0: lwarx %0,0,%1 ;" + " xor. %0,%3,%0;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + : "=&r"(ret) + : "r"(p), "r"(newval), "r"(oldval) + : "cr0", "memory"); + return ret == 0; +} + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/pthread/bits/libc-lock.h b/libpthread/linuxthreads.old/sysdeps/pthread/bits/libc-lock.h new file mode 100644 index 000000000..e2b267d32 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/pthread/bits/libc-lock.h @@ -0,0 +1,328 @@ +/* libc-internal interface for mutex locks. LinuxThreads version. + Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _BITS_LIBC_LOCK_H +#define _BITS_LIBC_LOCK_H 1 + +#include + +/* Mutex type. */ +#if defined(_LIBC) || defined(_IO_MTSAFE_IO) +typedef pthread_mutex_t __libc_lock_t; +typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; +# ifdef __USE_UNIX98 +typedef pthread_rwlock_t __libc_rwlock_t; +# else +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +# endif +#else +typedef struct __libc_lock_opaque__ __libc_lock_t; +typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; +typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; +#endif + +/* Type for key to thread-specific data. */ +typedef pthread_key_t __libc_key_t; + +/* Define a lock variable NAME with storage class CLASS. The lock must be + initialized with __libc_lock_init before it can be used (or define it + with __libc_lock_define_initialized, below). Use `extern' for CLASS to + declare a lock defined in another module. In public structure + definitions you must use a pointer to the lock structure (i.e., NAME + begins with a `*'), because its storage size will not be known outside + of libc. */ +#define __libc_lock_define(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +#define __libc_rwlock_define(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME; +#define __libc_lock_define_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME; + +/* Define an initialized lock variable NAME with storage class CLASS. + + For the C library we take a deeper look at the initializer. For + this implementation all fields are initialized to zero. Therefore + we don't initialize the variable which allows putting it into the + BSS section. (Except on PA-RISC and other odd architectures, where + initialized locks must be set to one due to the lack of normal + atomic operations.) */ + +#if __LT_SPINLOCK_INIT == 0 +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME; +#else +# define __libc_lock_define_initialized(CLASS,NAME) \ + CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER; +#endif + +#define __libc_rwlock_define_initialized(CLASS,NAME) \ + CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER; + +/* Define an initialized recursive lock variable NAME with storage + class CLASS. */ +#define __libc_lock_define_initialized_recursive(CLASS,NAME) \ + CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; +#define _LIBC_LOCK_RECURSIVE_INITIALIZER \ + {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} + +/* Initialize the named lock variable, leaving it in a consistent, unlocked + state. */ +#define __libc_lock_init(NAME) \ + (__pthread_mutex_init != NULL ? __pthread_mutex_init (&(NAME), NULL) : 0); +#define __libc_rwlock_init(NAME) \ + (__pthread_rwlock_init != NULL ? __pthread_rwlock_init (&(NAME), NULL) : 0); + +/* Same as last but this time we initialize a recursive mutex. */ +#define __libc_lock_init_recursive(NAME) \ + do { \ + if (__pthread_mutex_init != NULL) \ + { \ + pthread_mutexattr_t __attr; \ + __pthread_mutexattr_init (&__attr); \ + __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \ + __pthread_mutex_init (&(NAME).mutex, &__attr); \ + __pthread_mutexattr_destroy (&__attr); \ + } \ + } while (0); + +/* Finalize the named lock variable, which must be locked. It cannot be + used again until __libc_lock_init is called again on it. This must be + called on a lock variable before the containing storage is reused. */ +#define __libc_lock_fini(NAME) \ + (__pthread_mutex_destroy != NULL ? __pthread_mutex_destroy (&(NAME)) : 0); +#define __libc_rwlock_fini(NAME) \ + (__pthread_rwlock_destroy != NULL ? __pthread_rwlock_destroy (&(NAME)) : 0); + +/* Finalize recursive named lock. */ +#define __libc_lock_fini_recursive(NAME) __libc_lock_fini ((NAME).mutex) + +/* Lock the named lock variable. */ +#define __libc_lock_lock(NAME) \ + (__pthread_mutex_lock != NULL ? __pthread_mutex_lock (&(NAME)) : 0); +#define __libc_rwlock_rdlock(NAME) \ + (__pthread_rwlock_rdlock != NULL ? __pthread_rwlock_rdlock (&(NAME)) : 0); +#define __libc_rwlock_wrlock(NAME) \ + (__pthread_rwlock_wrlock != NULL ? __pthread_rwlock_wrlock (&(NAME)) : 0); + +/* Lock the recursive named lock variable. */ +#define __libc_lock_lock_recursive(NAME) __libc_lock_lock ((NAME).mutex) + +/* Try to lock the named lock variable. */ +#define __libc_lock_trylock(NAME) \ + (__pthread_mutex_trylock != NULL ? __pthread_mutex_trylock (&(NAME)) : 0) +#define __libc_rwlock_tryrdlock(NAME) \ + (__pthread_rwlock_tryrdlock != NULL \ + ? __pthread_rwlock_tryrdlock (&(NAME)) : 0) +#define __libc_rwlock_trywrlock(NAME) \ + (__pthread_rwlock_trywrlock != NULL \ + ? __pthread_rwlock_trywrlock (&(NAME)) : 0) + +/* Try to lock the recursive named lock variable. */ +#define __libc_lock_trylock_recursive(NAME) __libc_lock_trylock ((NAME).mutex) + +/* Unlock the named lock variable. */ +#define __libc_lock_unlock(NAME) \ + (__pthread_mutex_unlock != NULL ? __pthread_mutex_unlock (&(NAME)) : 0); +#define __libc_rwlock_unlock(NAME) \ + (__pthread_rwlock_unlock != NULL ? __pthread_rwlock_unlock (&(NAME)) : 0); + +/* Unlock the recursive named lock variable. */ +#define __libc_lock_unlock_recursive(NAME) __libc_lock_unlock ((NAME).mutex) + + +/* Define once control variable. */ +#if PTHREAD_ONCE_INIT == 0 +/* Special case for static variables where we can avoid the initialization + if it is zero. */ +# define __libc_once_define(CLASS, NAME) \ + CLASS pthread_once_t NAME +#else +# define __libc_once_define(CLASS, NAME) \ + CLASS pthread_once_t NAME = PTHREAD_ONCE_INIT +#endif + +/* Call handler iff the first call. */ +#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \ + do { \ + if (__pthread_once != NULL) \ + __pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \ + else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \ + INIT_FUNCTION (); \ + (ONCE_CONTROL) = !PTHREAD_ONCE_INIT; \ + } \ + } while (0) + + +/* Start critical region with cleanup. */ +#define __libc_cleanup_region_start(DOIT, FCT, ARG) \ + { struct _pthread_cleanup_buffer _buffer; \ + int _avail = (DOIT) && _pthread_cleanup_push_defer != NULL; \ + if (_avail) { \ + _pthread_cleanup_push_defer (&_buffer, (FCT), (ARG)); \ + } + +/* End critical region with cleanup. */ +#define __libc_cleanup_region_end(DOIT) \ + if (_avail) { \ + _pthread_cleanup_pop_restore (&_buffer, (DOIT)); \ + } \ + } + +/* Sometimes we have to exit the block in the middle. */ +#define __libc_cleanup_end(DOIT) \ + if (_avail) { \ + _pthread_cleanup_pop_restore (&_buffer, (DOIT)); \ + } + +/* Create thread-specific key. */ +#define __libc_key_create(KEY, DESTRUCTOR) \ + (__pthread_key_create != NULL ? __pthread_key_create (KEY, DESTRUCTOR) : 1) + +/* Get thread-specific data. */ +#define __libc_getspecific(KEY) \ + (__pthread_getspecific != NULL ? __pthread_getspecific (KEY) : NULL) + +/* Set thread-specific data. */ +#define __libc_setspecific(KEY, VALUE) \ + (__pthread_setspecific != NULL ? __pthread_setspecific (KEY, VALUE) : 0) + + +/* Register handlers to execute before and after `fork'. */ +#define __libc_atfork(PREPARE, PARENT, CHILD) \ + (__pthread_atfork != NULL ? __pthread_atfork (PREPARE, PARENT, CHILD) : 0) + +/* Functions that are used by this file and are internal to the GNU C + library. */ + +extern int __pthread_mutex_init (pthread_mutex_t *__mutex, + __const pthread_mutexattr_t *__mutex_attr); + +extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); + +extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); + +extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr); + +extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr); + +extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr, + int __kind); + +#ifdef __USE_UNIX98 +extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock, + __const pthread_rwlockattr_t *__attr); + +extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); + +extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); +#endif + +extern int __pthread_key_create (pthread_key_t *__key, + void (*__destr_function) (void *)); + +extern int __pthread_setspecific (pthread_key_t __key, + __const void *__pointer); + +extern void *__pthread_getspecific (pthread_key_t __key); + +extern int __pthread_once (pthread_once_t *__once_control, + void (*__init_routine) (void)); + +extern int __pthread_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void)); + + + +/* Make the pthread functions weak so that we can elide them from + single-threaded processes. */ +#ifndef __NO_WEAK_PTHREAD_ALIASES +# ifdef weak_extern +# if _LIBC +# include +# else +# define BP_SYM (sym) sym +# endif +weak_extern (BP_SYM (__pthread_mutex_init)) +weak_extern (BP_SYM (__pthread_mutex_destroy)) +weak_extern (BP_SYM (__pthread_mutex_lock)) +weak_extern (BP_SYM (__pthread_mutex_trylock)) +weak_extern (BP_SYM (__pthread_mutex_unlock)) +weak_extern (BP_SYM (__pthread_mutexattr_init)) +weak_extern (BP_SYM (__pthread_mutexattr_destroy)) +weak_extern (BP_SYM (__pthread_mutexattr_settype)) +weak_extern (BP_SYM (__pthread_rwlock_init)) +weak_extern (BP_SYM (__pthread_rwlock_destroy)) +weak_extern (BP_SYM (__pthread_rwlock_rdlock)) +weak_extern (BP_SYM (__pthread_rwlock_tryrdlock)) +weak_extern (BP_SYM (__pthread_rwlock_wrlock)) +weak_extern (BP_SYM (__pthread_rwlock_trywrlock)) +weak_extern (BP_SYM (__pthread_rwlock_unlock)) +weak_extern (BP_SYM (__pthread_key_create)) +weak_extern (BP_SYM (__pthread_setspecific)) +weak_extern (BP_SYM (__pthread_getspecific)) +weak_extern (BP_SYM (__pthread_once)) +weak_extern (__pthread_initialize) +weak_extern (__pthread_atfork) +weak_extern (BP_SYM (_pthread_cleanup_push_defer)) +weak_extern (BP_SYM (_pthread_cleanup_pop_restore)) +# else +# pragma weak __pthread_mutex_init +# pragma weak __pthread_mutex_destroy +# pragma weak __pthread_mutex_lock +# pragma weak __pthread_mutex_trylock +# pragma weak __pthread_mutex_unlock +# pragma weak __pthread_mutexattr_init +# pragma weak __pthread_mutexattr_destroy +# pragma weak __pthread_mutexattr_settype +# pragma weak __pthread_rwlock_destroy +# pragma weak __pthread_rwlock_rdlock +# pragma weak __pthread_rwlock_tryrdlock +# pragma weak __pthread_rwlock_wrlock +# pragma weak __pthread_rwlock_trywrlock +# pragma weak __pthread_rwlock_unlock +# pragma weak __pthread_key_create +# pragma weak __pthread_setspecific +# pragma weak __pthread_getspecific +# pragma weak __pthread_once +# pragma weak __pthread_initialize +# pragma weak __pthread_atfork +# pragma weak _pthread_cleanup_push_defer +# pragma weak _pthread_cleanup_pop_restore +# endif +#endif + +/* We need portable names for some functions. E.g., when they are + used as argument to __libc_cleanup_region_start. */ +#define __libc_mutex_unlock __pthread_mutex_unlock + +#endif /* bits/libc-lock.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/pthread/bits/libc-tsd.h b/libpthread/linuxthreads.old/sysdeps/pthread/bits/libc-tsd.h new file mode 100644 index 000000000..efd0c83be --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/pthread/bits/libc-tsd.h @@ -0,0 +1,66 @@ +/* libc-internal interface for thread-specific data. LinuxThreads version. + Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _BITS_LIBC_TSD_H +#define _BITS_LIBC_TSD_H 1 + +/* Fast thread-specific data internal to libc. */ +enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0, + _LIBC_TSD_KEY_DL_ERROR, + _LIBC_TSD_KEY_RPC_VARS, + _LIBC_TSD_KEY_LOCALE, + _LIBC_TSD_KEY_CTYPE_B, + _LIBC_TSD_KEY_CTYPE_TOLOWER, + _LIBC_TSD_KEY_CTYPE_TOUPPER, + _LIBC_TSD_KEY_N }; + +#include +#include + +#if USE_TLS && HAVE___THREAD + +/* When __thread works, the generic definition is what we want. */ +# include + +#else + +extern void *(*__libc_internal_tsd_get) (enum __libc_tsd_key_t) __THROW; +extern int (*__libc_internal_tsd_set) (enum __libc_tsd_key_t, + __const void *) __THROW; +extern void **(*const __libc_internal_tsd_address) (enum __libc_tsd_key_t) + __THROW __attribute__ ((__const__)); + +#define __libc_tsd_address(KEY) \ + (__libc_internal_tsd_address != NULL \ + ? __libc_internal_tsd_address (_LIBC_TSD_KEY_##KEY) \ + : &__libc_tsd_##KEY##_data) + +#define __libc_tsd_define(CLASS, KEY) CLASS void *__libc_tsd_##KEY##_data; +#define __libc_tsd_get(KEY) \ + (__libc_internal_tsd_get != NULL \ + ? __libc_internal_tsd_get (_LIBC_TSD_KEY_##KEY) \ + : __libc_tsd_##KEY##_data) +#define __libc_tsd_set(KEY, VALUE) \ + (__libc_internal_tsd_set != NULL \ + ? __libc_internal_tsd_set (_LIBC_TSD_KEY_##KEY, (VALUE)) \ + : ((__libc_tsd_##KEY##_data = (VALUE)), 0)) + +#endif + +#endif /* bits/libc-tsd.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/pthread/bits/pthreadtypes.h b/libpthread/linuxthreads.old/sysdeps/pthread/bits/pthreadtypes.h new file mode 100644 index 000000000..faec63b06 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/pthread/bits/pthreadtypes.h @@ -0,0 +1,142 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#if !defined _BITS_TYPES_H && !defined _PTHREAD_H +# error "Never include directly; use instead." +#endif + +#ifndef _BITS_PTHREADTYPES_H +#define _BITS_PTHREADTYPES_H 1 + +#define __need_schedparam +#include + +/* Fast locks (not abstract because mutexes and conditions aren't abstract). */ +struct _pthread_fastlock +{ + long int __status; /* "Free" or "taken" or head of waiting list */ + int __spinlock; /* Used by compare_and_swap emulation. Also, + adaptive SMP lock stores spin count here. */ +}; + +#ifndef _PTHREAD_DESCR_DEFINED +/* Thread descriptors */ +typedef struct _pthread_descr_struct *_pthread_descr; +# define _PTHREAD_DESCR_DEFINED +#endif + + +/* Attributes for threads. */ +typedef struct __pthread_attr_s +{ + int __detachstate; + int __schedpolicy; + struct __sched_param __schedparam; + int __inheritsched; + int __scope; + size_t __guardsize; + int __stackaddr_set; + void *__stackaddr; + size_t __stacksize; +} pthread_attr_t; + + +/* Conditions (not abstract because of PTHREAD_COND_INITIALIZER */ +typedef struct +{ + struct _pthread_fastlock __c_lock; /* Protect against concurrent access */ + _pthread_descr __c_waiting; /* Threads waiting on this condition */ +} pthread_cond_t; + + +/* Attribute for conditionally variables. */ +typedef struct +{ + int __dummy; +} pthread_condattr_t; + +/* Keys for thread-specific data */ +typedef unsigned int pthread_key_t; + + +/* Mutexes (not abstract because of PTHREAD_MUTEX_INITIALIZER). */ +/* (The layout is unnatural to maintain binary compatibility + with earlier releases of LinuxThreads.) */ +typedef struct +{ + int __m_reserved; /* Reserved for future use */ + int __m_count; /* Depth of recursive locking */ + _pthread_descr __m_owner; /* Owner thread (if recursive or errcheck) */ + int __m_kind; /* Mutex kind: fast, recursive or errcheck */ + struct _pthread_fastlock __m_lock; /* Underlying fast lock */ +} pthread_mutex_t; + + +/* Attribute for mutex. */ +typedef struct +{ + int __mutexkind; +} pthread_mutexattr_t; + + +/* Once-only execution */ +typedef int pthread_once_t; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Read-write locks. */ +typedef struct _pthread_rwlock_t +{ + struct _pthread_fastlock __rw_lock; /* Lock to guarantee mutual exclusion */ + int __rw_readers; /* Number of readers */ + _pthread_descr __rw_writer; /* Identity of writer, or NULL if none */ + _pthread_descr __rw_read_waiting; /* Threads waiting for reading */ + _pthread_descr __rw_write_waiting; /* Threads waiting for writing */ + int __rw_kind; /* Reader/Writer preference selection */ + int __rw_pshared; /* Shared between processes or not */ +} pthread_rwlock_t; + + +/* Attribute for read-write locks. */ +typedef struct +{ + int __lockkind; + int __pshared; +} pthread_rwlockattr_t; +#endif + +#ifdef __USE_XOPEN2K +/* POSIX spinlock data type. */ +typedef volatile int pthread_spinlock_t; + +/* POSIX barrier. */ +typedef struct { + struct _pthread_fastlock __ba_lock; /* Lock to guarantee mutual exclusion */ + int __ba_required; /* Threads needed for completion */ + int __ba_present; /* Threads waiting */ + _pthread_descr __ba_waiting; /* Queue of waiting threads */ +} pthread_barrier_t; + +/* barrier attribute */ +typedef struct { + int __pshared; +} pthread_barrierattr_t; + +#endif + + +/* Thread identifiers */ +typedef unsigned long int pthread_t; + +#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/pthread/pthread.h b/libpthread/linuxthreads.old/sysdeps/pthread/pthread.h new file mode 100644 index 000000000..6613cab88 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/pthread/pthread.h @@ -0,0 +1,705 @@ +/* Linuxthreads - a simple clone()-based implementation of Posix */ +/* threads for Linux. */ +/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ +/* */ +/* This program is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public License */ +/* as published by the Free Software Foundation; either version 2 */ +/* of the License, or (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU Library General Public License for more details. */ + +#ifndef _PTHREAD_H +#define _PTHREAD_H 1 + +#include + +#include +#include + +#define __need_sigset_t +#include +#include +#include +#ifdef _LIBC +#include +#endif + + +__BEGIN_DECLS + +/* Initializers. */ + +#define PTHREAD_MUTEX_INITIALIZER \ + {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER} +#ifdef __USE_GNU +# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ + {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER} +# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ + {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER} +# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ + {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER} +#endif + +#define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0} + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +# define PTHREAD_RWLOCK_INITIALIZER \ + { __LOCK_INITIALIZER, 0, NULL, NULL, NULL, \ + PTHREAD_RWLOCK_DEFAULT_NP, PTHREAD_PROCESS_PRIVATE } +#endif +#ifdef __USE_GNU +# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ + { __LOCK_INITIALIZER, 0, NULL, NULL, NULL, \ + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, PTHREAD_PROCESS_PRIVATE } +#endif + +/* Values for attributes. */ + +enum +{ + PTHREAD_CREATE_JOINABLE, +#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE + PTHREAD_CREATE_DETACHED +#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED +}; + +enum +{ + PTHREAD_INHERIT_SCHED, +#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED + PTHREAD_EXPLICIT_SCHED +#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED +}; + +enum +{ + PTHREAD_SCOPE_SYSTEM, +#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM + PTHREAD_SCOPE_PROCESS +#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS +}; + +enum +{ + PTHREAD_MUTEX_ADAPTIVE_NP, + PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_TIMED_NP +#ifdef __USE_UNIX98 + , + PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_ADAPTIVE_NP, + PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, + PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, + PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL +#endif +#ifdef __USE_GNU + /* For compatibility. */ + , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_ADAPTIVE_NP +#endif +}; + +enum +{ + PTHREAD_PROCESS_PRIVATE, +#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE + PTHREAD_PROCESS_SHARED +#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED +}; + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +enum +{ + PTHREAD_RWLOCK_PREFER_READER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, + PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_WRITER_NP +}; +#endif /* Unix98 */ + +#define PTHREAD_ONCE_INIT 0 + +/* Special constants */ + +#ifdef __USE_XOPEN2K +/* -1 is distinct from 0 and all errno constants */ +# define PTHREAD_BARRIER_SERIAL_THREAD -1 +#endif + +/* Cleanup buffers */ + +struct _pthread_cleanup_buffer +{ + void (*__routine) (void *); /* Function to call. */ + void *__arg; /* Its argument. */ + int __canceltype; /* Saved cancellation type. */ + struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions. */ +}; + +/* Cancellation */ + +enum +{ + PTHREAD_CANCEL_ENABLE, +#define PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ENABLE + PTHREAD_CANCEL_DISABLE +#define PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_DISABLE +}; +enum +{ + PTHREAD_CANCEL_DEFERRED, +#define PTHREAD_CANCEL_DEFERRED PTHREAD_CANCEL_DEFERRED + PTHREAD_CANCEL_ASYNCHRONOUS +#define PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ASYNCHRONOUS +}; +#define PTHREAD_CANCELED ((void *) -1) + + +/* Function for handling threads. */ + +/* Create a thread with given attributes ATTR (or default attributes + if ATTR is NULL), and call function START_ROUTINE with given + arguments ARG. */ +extern int pthread_create (pthread_t *__restrict __threadp, + __const pthread_attr_t *__restrict __attr, + void *(*__start_routine) (void *), + void *__restrict __arg) __THROW; + +/* Obtain the identifier of the current thread. */ +extern pthread_t pthread_self (void) __THROW; + +/* Compare two thread identifiers. */ +extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW; + +/* Terminate calling thread. */ +extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__)); + +/* Make calling thread wait for termination of the thread TH. The + exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN + is not NULL. */ +extern int pthread_join (pthread_t __th, void **__thread_return); + +/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN. + The resources of TH will therefore be freed immediately when it + terminates, instead of waiting for another thread to perform PTHREAD_JOIN + on it. */ +extern int pthread_detach (pthread_t __th) __THROW; + + +/* Functions for handling attributes. */ + +/* Initialize thread attribute *ATTR with default attributes + (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, + no user-provided stack). */ +extern int pthread_attr_init (pthread_attr_t *__attr) __THROW; + +/* Destroy thread attribute *ATTR. */ +extern int pthread_attr_destroy (pthread_attr_t *__attr) __THROW; + +/* Set the `detachstate' attribute in *ATTR according to DETACHSTATE. */ +extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, + int __detachstate) __THROW; + +/* Return in *DETACHSTATE the `detachstate' attribute in *ATTR. */ +extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr, + int *__detachstate) __THROW; + +/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM. */ +extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr, + __const struct sched_param *__restrict + __param) __THROW; + +/* Return in *PARAM the scheduling parameters of *ATTR. */ +extern int pthread_attr_getschedparam (__const pthread_attr_t *__restrict + __attr, + struct sched_param *__restrict __param) + __THROW; + +/* Set scheduling policy in *ATTR according to POLICY. */ +extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) + __THROW; + +/* Return in *POLICY the scheduling policy of *ATTR. */ +extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict + __attr, int *__restrict __policy) + __THROW; + +/* Set scheduling inheritance mode in *ATTR according to INHERIT. */ +extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, + int __inherit) __THROW; + +/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */ +extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict + __attr, int *__restrict __inherit) + __THROW; + +/* Set scheduling contention scope in *ATTR according to SCOPE. */ +extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) + __THROW; + +/* Return in *SCOPE the scheduling contention scope of *ATTR. */ +extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr, + int *__restrict __scope) __THROW; + +#ifdef __USE_UNIX98 +/* Set the size of the guard area at the bottom of the thread. */ +extern int pthread_attr_setguardsize (pthread_attr_t *__attr, + size_t __guardsize) __THROW; + +/* Get the size of the guard area at the bottom of the thread. */ +extern int pthread_attr_getguardsize (__const pthread_attr_t *__restrict + __attr, size_t *__restrict __guardsize) + __THROW; +#endif + +/* Set the starting address of the stack of the thread to be created. + Depending on whether the stack grows up or down the value must either + be higher or lower than all the address in the memory block. The + minimal size of the block must be PTHREAD_STACK_SIZE. */ +extern int pthread_attr_setstackaddr (pthread_attr_t *__attr, + void *__stackaddr) __THROW; + +/* Return the previously set address for the stack. */ +extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict + __attr, void **__restrict __stackaddr) + __THROW; + +#ifdef __USE_XOPEN2K +/* The following two interfaces are intended to replace the last two. They + require setting the address as well as the size since only setting the + address will make the implementation on some architectures impossible. */ +extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, + size_t __stacksize) __THROW; + +/* Return the previously set address for the stack. */ +extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr, + void **__restrict __stackaddr, + size_t *__restrict __stacksize) __THROW; +#endif + +/* Add information about the minimum stack size needed for the thread + to be started. This size must never be less than PTHREAD_STACK_SIZE + and must also not exceed the system limits. */ +extern int pthread_attr_setstacksize (pthread_attr_t *__attr, + size_t __stacksize) __THROW; + +/* Return the currently used minimal stack size. */ +extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict + __attr, size_t *__restrict __stacksize) + __THROW; + +#if 0 +/* Not yet implemented in uClibc! */ + +#ifdef __USE_GNU +/* Initialize thread attribute *ATTR with attributes corresponding to the + already running thread TH. It shall be called on unitialized ATTR + and destroyed with pthread_attr_destroy when no longer needed. */ +extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW; +#endif +#endif + +/* Functions for scheduling control. */ + +/* Set the scheduling parameters for TARGET_THREAD according to POLICY + and *PARAM. */ +extern int pthread_setschedparam (pthread_t __target_thread, int __policy, + __const struct sched_param *__param) + __THROW; + +/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */ +extern int pthread_getschedparam (pthread_t __target_thread, + int *__restrict __policy, + struct sched_param *__restrict __param) + __THROW; + +#ifdef __USE_UNIX98 +/* Determine level of concurrency. */ +extern int pthread_getconcurrency (void) __THROW; + +/* Set new concurrency level to LEVEL. */ +extern int pthread_setconcurrency (int __level) __THROW; +#endif + +#if 0 +/* Not yet implemented in uClibc! */ + +#ifdef __USE_GNU +/* Yield the processor to another thread or process. + This function is similar to the POSIX `sched_yield' function but + might be differently implemented in the case of a m-on-n thread + implementation. */ +extern int pthread_yield (void) __THROW; +#endif +#endif + +/* Functions for mutex handling. */ + +/* Initialize MUTEX using attributes in *MUTEX_ATTR, or use the + default values if later is NULL. */ +extern int pthread_mutex_init (pthread_mutex_t *__restrict __mutex, + __const pthread_mutexattr_t *__restrict + __mutex_attr) __THROW; + +/* Destroy MUTEX. */ +extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW; + +/* Try to lock MUTEX. */ +extern int pthread_mutex_trylock (pthread_mutex_t *__mutex) __THROW; + +/* Wait until lock for MUTEX becomes available and lock it. */ +extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW; + +#ifdef __USE_XOPEN2K +/* Wait until lock becomes available, or specified time passes. */ +extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, + __const struct timespec *__restrict + __abstime) __THROW; +#endif + +/* Unlock MUTEX. */ +extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW; + + +/* Functions for handling mutex attributes. */ + +/* Initialize mutex attribute object ATTR with default attributes + (kind is PTHREAD_MUTEX_TIMED_NP). */ +extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW; + +/* Destroy mutex attribute object ATTR. */ +extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW; + +/* Get the process-shared flag of the mutex attribute ATTR. */ +extern int pthread_mutexattr_getpshared (__const pthread_mutexattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the mutex attribute ATTR. */ +extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, + int __pshared) __THROW; + +#ifdef __USE_UNIX98 +/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL, + PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or + PTHREAD_MUTEX_DEFAULT). */ +extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) + __THROW; + +/* Return in *KIND the mutex kind attribute in *ATTR. */ +extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict + __attr, int *__restrict __kind) __THROW; +#endif + + +/* Functions for handling conditional variables. */ + +/* Initialize condition variable COND using attributes ATTR, or use + the default values if later is NULL. */ +extern int pthread_cond_init (pthread_cond_t *__restrict __cond, + __const pthread_condattr_t *__restrict + __cond_attr) __THROW; + +/* Destroy condition variable COND. */ +extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW; + +/* Wake up one thread waiting for condition variable COND. */ +extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW; + +/* Wake up all threads waiting for condition variables COND. */ +extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW; + +/* Wait for condition variable COND to be signaled or broadcast. + MUTEX is assumed to be locked before. */ +extern int pthread_cond_wait (pthread_cond_t *__restrict __cond, + pthread_mutex_t *__restrict __mutex); + +/* Wait for condition variable COND to be signaled or broadcast until + ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an + absolute time specification; zero is the beginning of the epoch + (00:00:00 GMT, January 1, 1970). */ +extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond, + pthread_mutex_t *__restrict __mutex, + __const struct timespec *__restrict + __abstime); + +/* Functions for handling condition variable attributes. */ + +/* Initialize condition variable attribute ATTR. */ +extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW; + +/* Destroy condition variable attribute ATTR. */ +extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW; + +/* Get the process-shared flag of the condition variable attribute ATTR. */ +extern int pthread_condattr_getpshared (__const pthread_condattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +/* Set the process-shared flag of the condition variable attribute ATTR. */ +extern int pthread_condattr_setpshared (pthread_condattr_t *__attr, + int __pshared) __THROW; + + +#if defined __USE_UNIX98 || defined __USE_XOPEN2K +/* Functions for handling read-write locks. */ + +/* Initialize read-write lock RWLOCK using attributes ATTR, or use + the default values if later is NULL. */ +extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, + __const pthread_rwlockattr_t *__restrict + __attr) __THROW; + +/* Destroy read-write lock RWLOCK. */ +extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) __THROW; + +/* Acquire read lock for RWLOCK. */ +extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire read lock for RWLOCK. */ +extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire read lock for RWLOCK or return after specfied time. */ +extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, + __const struct timespec *__restrict + __abstime) __THROW; +# endif + +/* Acquire write lock for RWLOCK. */ +extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW; + +/* Try to acquire write lock for RWLOCK. */ +extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW; + +# ifdef __USE_XOPEN2K +/* Try to acquire write lock for RWLOCK or return after specfied time. */ +extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, + __const struct timespec *__restrict + __abstime) __THROW; +# endif + +/* Unlock RWLOCK. */ +extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW; + + +/* Functions for handling read-write lock attributes. */ + +/* Initialize attribute object ATTR with default values. */ +extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) __THROW; + +/* Destroy attribute object ATTR. */ +extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) __THROW; + +/* Return current setting of process-shared attribute of ATTR in PSHARED. */ +extern int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +/* Set process-shared attribute of ATTR to PSHARED. */ +extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, + int __pshared) __THROW; + +/* Return current setting of reader/writer preference. */ +extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t *__attr, + int *__pref) __THROW; + +/* Set reader/write preference. */ +extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, + int __pref) __THROW; +#endif + +#if 0 +/* Not yet implemented in uClibc! */ + +#ifdef __USE_XOPEN2K +/* The IEEE Std. 1003.1j-2000 introduces functions to implement + spinlocks. */ + +/* Initialize the spinlock LOCK. If PSHARED is nonzero the spinlock can + be shared between different processes. */ +extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared) + __THROW; + +/* Destroy the spinlock LOCK. */ +extern int pthread_spin_destroy (pthread_spinlock_t *__lock) __THROW; + +/* Wait until spinlock LOCK is retrieved. */ +extern int pthread_spin_lock (pthread_spinlock_t *__lock) __THROW; + +/* Try to lock spinlock LOCK. */ +extern int pthread_spin_trylock (pthread_spinlock_t *__lock) __THROW; + +/* Release spinlock LOCK. */ +extern int pthread_spin_unlock (pthread_spinlock_t *__lock) __THROW; + + +/* Barriers are a also a new feature in 1003.1j-2000. */ + +extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier, + __const pthread_barrierattr_t *__restrict + __attr, unsigned int __count) __THROW; + +extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW; + +extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW; + +extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW; + +extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t * + __restrict __attr, + int *__restrict __pshared) __THROW; + +extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, + int __pshared) __THROW; + +extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW; +#endif +#endif + + +/* Functions for handling thread-specific data. */ + +/* Create a key value identifying a location in the thread-specific + data area. Each thread maintains a distinct thread-specific data + area. DESTR_FUNCTION, if non-NULL, is called with the value + associated to that key when the key is destroyed. + DESTR_FUNCTION is not called if the value associated is NULL when + the key is destroyed. */ +extern int pthread_key_create (pthread_key_t *__key, + void (*__destr_function) (void *)) __THROW; + +/* Destroy KEY. */ +extern int pthread_key_delete (pthread_key_t __key) __THROW; + +/* Store POINTER in the thread-specific data slot identified by KEY. */ +extern int pthread_setspecific (pthread_key_t __key, + __const void *__pointer) __THROW; + +/* Return current value of the thread-specific data slot identified by KEY. */ +extern void *pthread_getspecific (pthread_key_t __key) __THROW; + + +/* Functions for handling initialization. */ + +/* Guarantee that the initialization function INIT_ROUTINE will be called + only once, even if pthread_once is executed several times with the + same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or + extern variable initialized to PTHREAD_ONCE_INIT. + + The initialization functions might throw exception which is why + this function is not marked with __THROW. */ +extern int pthread_once (pthread_once_t *__once_control, + void (*__init_routine) (void)); + + +/* Functions for handling cancellation. */ + +/* Set cancelability state of current thread to STATE, returning old + state in *OLDSTATE if OLDSTATE is not NULL. */ +extern int pthread_setcancelstate (int __state, int *__oldstate); + +/* Set cancellation state of current thread to TYPE, returning the old + type in *OLDTYPE if OLDTYPE is not NULL. */ +extern int pthread_setcanceltype (int __type, int *__oldtype); + +/* Cancel THREAD immediately or at the next possibility. */ +extern int pthread_cancel (pthread_t __cancelthread); + +/* Test for pending cancellation for the current thread and terminate + the thread as per pthread_exit(PTHREAD_CANCELED) if it has been + cancelled. */ +extern void pthread_testcancel (void); + + +/* Install a cleanup handler: ROUTINE will be called with arguments ARG + when the thread is cancelled or calls pthread_exit. ROUTINE will also + be called with arguments ARG when the matching pthread_cleanup_pop + is executed with non-zero EXECUTE argument. + pthread_cleanup_push and pthread_cleanup_pop are macros and must always + be used in matching pairs at the same nesting level of braces. */ + +#define pthread_cleanup_push(routine,arg) \ + { struct _pthread_cleanup_buffer _buffer; \ + _pthread_cleanup_push (&_buffer, (routine), (arg)); + +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg) __THROW; + +/* Remove a cleanup handler installed by the matching pthread_cleanup_push. + If EXECUTE is non-zero, the handler function is called. */ + +#define pthread_cleanup_pop(execute) \ + _pthread_cleanup_pop (&_buffer, (execute)); } + +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, + int __execute) __THROW; + +/* Install a cleanup handler as pthread_cleanup_push does, but also + saves the current cancellation type and set it to deferred cancellation. */ + +#ifdef __USE_GNU +# define pthread_cleanup_push_defer_np(routine,arg) \ + { struct _pthread_cleanup_buffer _buffer; \ + _pthread_cleanup_push_defer (&_buffer, (routine), (arg)); + +extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg) __THROW; + +/* Remove a cleanup handler as pthread_cleanup_pop does, but also + restores the cancellation type that was in effect when the matching + pthread_cleanup_push_defer was called. */ + +# define pthread_cleanup_pop_restore_np(execute) \ + _pthread_cleanup_pop_restore (&_buffer, (execute)); } + +extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer, + int __execute) __THROW; +#endif + + +#if 0 +/* Not yet implemented in uClibc! */ + +#ifdef __USE_XOPEN2K +/* Get ID of CPU-time clock for thread THREAD_ID. */ +extern int pthread_getcpuclockid (pthread_t __thread_id, + clockid_t *__clock_id) __THROW; +#endif +#endif + + +/* Functions for handling signals. */ +#include + + +/* Functions for handling process creation and process execution. */ + +/* Install handlers to be called when a new process is created with FORK. + The PREPARE handler is called in the parent process just before performing + FORK. The PARENT handler is called in the parent process just after FORK. + The CHILD handler is called in the child process. Each of the three + handlers can be NULL, meaning that no handler needs to be called at that + point. + PTHREAD_ATFORK can be called several times, in which case the PREPARE + handlers are called in LIFO order (last added with PTHREAD_ATFORK, + first called before FORK), and the PARENT and CHILD handlers are called + in FIFO (first added, first called). */ + +extern int pthread_atfork (void (*__prepare) (void), + void (*__parent) (void), + void (*__child) (void)) __THROW; + +/* Terminate all threads in the program except the calling process. + Should be called just before invoking one of the exec*() functions. */ + +extern void pthread_kill_other_threads_np (void) __THROW; + +__END_DECLS + +#endif /* pthread.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/pthread/tls.h b/libpthread/linuxthreads.old/sysdeps/pthread/tls.h new file mode 100644 index 000000000..6a23ec05e --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/pthread/tls.h @@ -0,0 +1,81 @@ +/* Definition for thread-local data handling. Generic version. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* By default no TLS support is available. This is signaled by the + absence of the symbol USE_TLS. */ +#undef USE_TLS + + +/* An architecture-specific version of this file has to defined a + number of symbols: + + TLS_TCB_AT_TP or TLS_DTV_AT_TP + + The presence of one of these symbols signals which variant of + the TLS ABI is used. There are in the moment two variants + available: + + * the thread pointer points to a thread control block + + * the thread pointer points to the dynamic thread vector + + + TLS_TCB_SIZE + + This is the size of the thread control block structure. How + this is actually defined depends on the ABI. The thread control + block could be internal descriptor of the thread library or + just a data structure which allows finding the DTV. + + TLS_INIT_TCB_SIZE + + Similarly, but this value is only used at startup and in the + dynamic linker itself. There are no threads in use at that time. + + + TLS_TCB_ALIGN + + Alignment requirements for the TCB structure. + + TLS_INIT_TCB_ALIGN + + Similarly, but for the structure used at startup time. + + + INSTALL_DTV(tcb, init_dtv) + + This macro must install the given initial DTV into the thread control + block TCB. The normal runtime functionality must then be able to + use the value. + + + TLS_INIT_TP(tcb, firstcall) + + This macro must initialize the thread pointer to enable normal TLS + operation. The first parameter is a pointer to the thread control + block. The second parameter specifies whether this is the first + call for the TCB. ld.so calls this macro more than once. + + + THREAD_DTV() + + This macro returns the address of the DTV of the current thread. + This normally is done using the the thread register which points + to the dtv or the TCB (from which the DTV can found). + */ diff --git a/libpthread/linuxthreads.old/sysdeps/sh/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/sh/pt-machine.h new file mode 100644 index 000000000..02545e6b4 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/sh/pt-machine.h @@ -0,0 +1,81 @@ +/* Machine-dependent pthreads configuration and inline functions. + SuperH version. + Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Niibe Yutaka . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef __ASSEMBLER__ +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__( + "tas.b @%1\n\t" + "movt %0" + : "=r" (ret) + : "r" (spinlock) + : "memory", "cc"); + + return (ret == 0); +} + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("r15"); + +/* Return the thread descriptor for the current thread. */ +struct _pthread_descr_struct; +#define THREAD_SELF \ + ({ struct _pthread_descr_struct *self; \ + __asm__("stc gbr,%0" : "=r" (self)); self;}) + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) \ + ({ __asm__ __volatile__("ldc %0,gbr" : : "r" (descr));}) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#endif /* __ASSEMBLER__ */ + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/sh/tls.h b/libpthread/linuxthreads.old/sysdeps/sh/tls.h new file mode 100644 index 000000000..75326d8e1 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/sh/tls.h @@ -0,0 +1,117 @@ +/* Definition for thread-local data handling. linuxthreads/SH version. + Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +# include + +#ifndef __ASSEMBLER__ +# include +# include +# include + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + void *pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ +} tcbhead_t; + + +/* We can support TLS only if the floating-stack support is available. */ +#if defined FLOATING_STACKS && defined HAVE_TLS_SUPPORT + +/* Get system call information. */ +# include + +/* Signal that TLS support is available. */ +//# define USE_TLS 1 + + +/* Get the thread descriptor definition. */ +# include + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* The TLS blocks start right after the TCB. */ +# define TLS_DTV_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = dtvp + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(descr, secondcall) \ + ({ \ + void *_descr = (descr); \ + int result; \ + tcbhead_t *head = _descr; \ + \ + head->tcb = _descr; \ + /* For now the thread descriptor is at the same address. */ \ + head->self = _descr; \ + \ + asm ("ldc %0,gbr" : : "r" (_descr)); \ + \ + 0; \ + }) + + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_GETMEM (__descr, p_header.data.dtvp); }) + +#endif /* FLOATING_STACKS && HAVE_TLS_SUPPORT */ +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/sh64/Makefile.arch b/libpthread/linuxthreads.old/sysdeps/sh64/Makefile.arch new file mode 100644 index 000000000..38cd12db6 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/sh64/Makefile.arch @@ -0,0 +1,26 @@ +# Makefile for uClibc +# +# Copyright (C) 2003 Paul Mundt +# Copyright (C) 2000-2005 Erik Andersen +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +# We need to build as SHcompact for tas.. +ARCH_CFLAGS:=$(subst 32media,compact,$(ARCH_CFLAGS)) + +libpthread_ARCH_DIR:=$(top_srcdir)libpthread/linuxthreads/sysdeps/sh64 +libpthread_ARCH_OUT:=$(top_builddir)libpthread/linuxthreads/sysdeps/sh64 + +libpthread_ARCH_SRC:=$(wildcard $(libpthread_ARCH_DIR)/*.c) +libpthread_ARCH_OBJ:=$(patsubst $(libpthread_ARCH_DIR)/%.c,$(libpthread_ARCH_OUT)/%.o,$(libpthread_ARCH_SRC)) + +libpthread-a-$(UCLIBC_HAS_THREADS)+=$(libpthread_ARCH_OBJ) +libpthread-so-$(UCLIBC_HAS_THREADS)+=$(libpthread_ARCH_OBJ:.o=.os) + +libpthread-multi-$(UCLIBC_HAS_THREADS)+=$(libpthread_ARCH_SRC) + +objclean-y+=libpthread_arch_objclean + +libpthread_arch_objclean: + $(RM) $(libpthread_ARCH_OUT)/*.{o,os} diff --git a/libpthread/linuxthreads.old/sysdeps/sh64/pt-machine.c b/libpthread/linuxthreads.old/sysdeps/sh64/pt-machine.c new file mode 100644 index 000000000..ea4881322 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/sh64/pt-machine.c @@ -0,0 +1,47 @@ +/* Cloned for uClibc by Paul Mundt, December 2003 */ +/* Modified by SuperH, Inc. September 2003 */ + +/* Machine-dependent pthreads configuration and inline functions. + SH5 version. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Niibe Yutaka . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "pt-machine.h" + +/* Spinlock implementation; required. */ + +/* The SH5 does not have a suitable test-and-set instruction (SWAP only + operates on an aligned quad word). So we use the SH4 version instead. + This must be seperately compiled in SHcompact mode, so it cannot be + inline. */ + +long int testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__( + "tas.b @%1\n\t" + "movt %0" + : "=r" (ret) + : "r" (spinlock) + : "memory", "cc"); + + return (ret == 0); +} + diff --git a/libpthread/linuxthreads.old/sysdeps/sh64/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/sh64/pt-machine.h new file mode 100644 index 000000000..8269a4cb3 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/sh64/pt-machine.h @@ -0,0 +1,36 @@ +/* Cloned for uClibc by Paul Mundt, December 2003 */ +/* Modified by SuperH, Inc. September 2003 */ + +/* Machine-dependent pthreads configuration and inline functions. + SuperH version. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Niibe Yutaka . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef PT_EI +# define PT_EI extern inline +#endif + +/* Spinlock implementation; required. */ +extern long int testandset (int *spinlock); + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("r15"); diff --git a/libpthread/linuxthreads.old/sysdeps/sparc/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/sparc/pt-machine.h new file mode 100644 index 000000000..ab90810f1 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/sparc/pt-machine.h @@ -0,0 +1,8 @@ +#include +#include + +#if __WORDSIZE == 32 +# include "sparc32/pt-machine.h" +#else +# include "sparc64/pt-machine.h" +#endif diff --git a/libpthread/linuxthreads.old/sysdeps/sparc/sparc32/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/sparc/sparc32/pt-machine.h new file mode 100644 index 000000000..322a52051 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/sparc/sparc32/pt-machine.h @@ -0,0 +1,83 @@ +/* Machine-dependent pthreads configuration and inline functions. + sparc version. + Copyright (C) 1996-1998, 2000-2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__("ldstub %1,%0" + : "=r"(ret), "=m"(*spinlock) + : "m"(*spinlock)); + + return ret; +} + + +/* Memory barrier; default is to do nothing */ +#define MEMORY_BARRIER() __asm__ __volatile__("stbar" : : : "memory") + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME (stack_pointer + (2 * 64)) +register char *stack_pointer __asm__("%sp"); + + +/* Registers %g6 and %g7 are reserved by the ABI for "system use". + %g7 is specified in the TLS ABI as thread pointer -- we do the same. */ +struct _pthread_descr_struct; +register struct _pthread_descr_struct *__thread_self __asm__("%g7"); + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 8*1024*1024 + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/sparc/sparc64/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/sparc/sparc64/pt-machine.h new file mode 100644 index 000000000..f65c13be1 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/sparc/sparc64/pt-machine.h @@ -0,0 +1,105 @@ +/* Machine-dependent pthreads configuration and inline functions. + Sparc v9 version. + Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +#endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + int ret; + + __asm__ __volatile__("ldstub %1,%0" + : "=r" (ret), "=m" (*spinlock) : "m" (*spinlock)); + + return ret; +} + + +/* Memory barrier; default is to do nothing */ +#define MEMORY_BARRIER() \ + __asm__ __volatile__("membar #LoadLoad | #LoadStore | #StoreLoad | #StoreStore" : : : "memory") +/* Read barrier. */ +#define READ_MEMORY_BARRIER() \ + __asm__ __volatile__("membar #LoadLoad | #LoadStore" : : : "memory") +/* Write barrier. */ +#define WRITE_MEMORY_BARRIER() \ + __asm__ __volatile__("membar #StoreLoad | #StoreStore" : : : "memory") + + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME (stack_pointer + (2 * 128)) +register char *stack_pointer __asm__ ("%sp"); + + +/* Registers %g6 and %g7 are reserved by the ABI for "system use". The + TLS ABI specifies %g7 as the thread pointer. */ +struct _pthread_descr_struct; +register struct _pthread_descr_struct *__thread_self __asm__ ("%g7"); + +/* Return the thread descriptor for the current thread. */ +#define THREAD_SELF __thread_self + +/* Initialize the thread-unique value. */ +#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) + + +/* Compare-and-swap for semaphores. */ + +#define HAS_COMPARE_AND_SWAP +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + long int readval; + + __asm__ __volatile__ ("casx [%4], %2, %0" + : "=r"(readval), "=m"(*p) + : "r"(oldval), "m"(*p), "r"(p), "0"(newval)); + MEMORY_BARRIER(); + return readval == oldval; +} + +/* Access to data in the thread descriptor is easy. */ +#define THREAD_GETMEM(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_GETMEM_NC(descr, member) \ + ((void) sizeof (descr), THREAD_SELF->member) +#define THREAD_SETMEM(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) +#define THREAD_SETMEM_NC(descr, member, value) \ + ((void) sizeof (descr), THREAD_SELF->member = (value)) + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/v850/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/v850/pt-machine.h new file mode 100644 index 000000000..fb41c41e9 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/v850/pt-machine.h @@ -0,0 +1,46 @@ +/* + * sysdeps/v850/pt-machine.h -- v850-specific pthread definitions + * + * Copyright (C) 2002 NEC Electronics Corporation + * Copyright (C) 2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License. See the file COPYING.LIB in the main + * directory of this archive for more details. + * + * Written by Miles Bader + */ + +#ifndef PT_EI +# define PT_EI extern inline +#endif + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +#define CURRENT_STACK_FRAME __stack_pointer +register char *__stack_pointer __asm__ ("sp"); + +#define HAS_COMPARE_AND_SWAP + +/* Atomically: If *PTR == OLD, set *PTR to NEW and return true, + otherwise do nothing and return false. */ +PT_EI int +__compare_and_swap (long *ptr, long old, long new) +{ + unsigned long psw; + + /* disable interrupts */ + __asm__ __volatile__ ("stsr psw, %0; di" : "=&r" (psw)); + + if (likely (*ptr == old)) + { + *ptr = new; + __asm__ __volatile__ ("ldsr %0, psw" :: "r" (psw)); /* re-enable */ + return 1; + } + else + { + __asm__ __volatile__ ("ldsr %0, psw" :: "r" (psw)); /* re-enable */ + return 0; + } +} diff --git a/libpthread/linuxthreads.old/sysdeps/x86_64/pt-machine.h b/libpthread/linuxthreads.old/sysdeps/x86_64/pt-machine.h new file mode 100644 index 000000000..8a2d1a762 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/x86_64/pt-machine.h @@ -0,0 +1,86 @@ +/* Machine-dependent pthreads configuration and inline functions. + x86-64 version. + Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _PT_MACHINE_H +#define _PT_MACHINE_H 1 + +#ifndef __ASSEMBLER__ +# include /* For offsetof. */ +# include /* For abort(). */ +# include + + +# ifndef PT_EI +# define PT_EI extern inline __attribute__ ((always_inline)) +# endif + +extern long int testandset (int *spinlock); +extern int __compare_and_swap (long int *p, long int oldval, long int newval); + +/* Get some notion of the current stack. Need not be exactly the top + of the stack, just something somewhere in the current frame. */ +# define CURRENT_STACK_FRAME stack_pointer +register char * stack_pointer __asm__ ("%rsp") __attribute_used__; + + +/* Spinlock implementation; required. */ +PT_EI long int +testandset (int *spinlock) +{ + long int ret; + + __asm__ __volatile__ ( + "xchgl %k0, %1" + : "=r"(ret), "=m"(*spinlock) + : "0"(1), "m"(*spinlock) + : "memory"); + + return ret; +} + + +/* Compare-and-swap for semaphores. */ +# define HAS_COMPARE_AND_SWAP + +PT_EI int +__compare_and_swap (long int *p, long int oldval, long int newval) +{ + char ret; + long int readval; + + __asm__ __volatile__ ("lock; cmpxchgq %3, %1; sete %0" + : "=q" (ret), "=m" (*p), "=a" (readval) + : "r" (newval), "m" (*p), "a" (oldval) + : "memory"); + return ret; +} + +#endif /* !__ASSEMBLER__ */ + +/* We want the OS to assign stack addresses. */ +#define FLOATING_STACKS 1 + +/* Maximum size of the stack if the rlimit is unlimited. */ +#define ARCH_STACK_MAX_SIZE 32*1024*1024 + +/* The ia32e really want some help to prevent overheating. */ +#define BUSY_WAIT_NOP __asm__ ("rep; nop") + +#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads.old/sysdeps/x86_64/tls.h b/libpthread/linuxthreads.old/sysdeps/x86_64/tls.h new file mode 100644 index 000000000..d67275c10 --- /dev/null +++ b/libpthread/linuxthreads.old/sysdeps/x86_64/tls.h @@ -0,0 +1,134 @@ +/* Definitions for thread-local data handling. linuxthreads/x86-64 version. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TLS_H +#define _TLS_H + +#ifndef __ASSEMBLER__ + +# include +# include +# include + +/* Type for the dtv. */ +typedef union dtv +{ + size_t counter; + struct + { + void *val; + bool is_static; + } pointer; +} dtv_t; + + +typedef struct +{ + void *tcb; /* Pointer to the TCB. Not necessary the + thread descriptor used by libpthread. */ + dtv_t *dtv; + void *self; /* Pointer to the thread descriptor. */ + int multiple_threads; +} tcbhead_t; + +#else /* __ASSEMBLER__ */ +# include +#endif + + +#ifdef HAVE_TLS_SUPPORT + +/* Signal that TLS support is available. */ +# define USE_TLS 1 + +# ifndef __ASSEMBLER__ +/* Get system call information. */ +# include + +/* Get the thread descriptor definition. */ +# include + +/* This is the size of the initial TCB. */ +# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) + +/* Alignment requirements for the initial TCB. */ +# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) + +/* This is the size of the TCB. */ +# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) + +/* Alignment requirements for the TCB. */ +# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) + +/* The TCB can have any size and the memory following the address the + thread pointer points to is unspecified. Allocate the TCB there. */ +# define TLS_TCB_AT_TP 1 + + +/* Install the dtv pointer. The pointer passed is to the element with + index -1 which contain the length. */ +# define INSTALL_DTV(descr, dtvp) \ + ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 + +/* Install new dtv for current thread. */ +# define INSTALL_NEW_DTV(dtv) \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); }) + +/* Return dtv of given thread descriptor. */ +# define GET_DTV(descr) \ + (((tcbhead_t *) (descr))->dtv) + +/* Code to initially initialize the thread pointer. This might need + special attention since 'errno' is not yet available and if the + operation can cause a failure 'errno' must not be touched. */ +# define TLS_INIT_TP(descr, secondcall) \ + ({ \ + void *_descr = (descr); \ + tcbhead_t *head = _descr; \ + long int _result; \ + \ + head->tcb = _descr; \ + /* For now the thread descriptor is at the same address. */ \ + head->self = _descr; \ + \ + asm volatile ("syscall" \ + : "=a" (_result) \ + : "0" ((unsigned long int) __NR_arch_prctl), \ + "D" ((unsigned long int) ARCH_SET_FS), \ + "S" (_descr) \ + : "memory", "cc", "r11", "cx"); \ + \ + _result ? "cannot set %fs base address for thread-local storage" : 0; \ + }) + +/* Indicate that dynamic linker shouldn't try to initialize TLS even + when no PT_TLS segments are found in the program and libraries + it is linked against. */ +# define TLS_INIT_TP_EXPENSIVE 1 + +/* Return the address of the dtv for the current thread. */ +# define THREAD_DTV() \ + ({ struct _pthread_descr_struct *__descr; \ + THREAD_GETMEM (__descr, p_header.data.dtvp); }) + +# endif /* HAVE_TLS_SUPPORT */ +#endif /* __ASSEMBLER__ */ + +#endif /* tls.h */ diff --git a/libpthread/linuxthreads.old/wrapsyscall.c b/libpthread/linuxthreads.old/wrapsyscall.c new file mode 100644 index 000000000..6b8a00bb5 --- /dev/null +++ b/libpthread/linuxthreads.old/wrapsyscall.c @@ -0,0 +1,220 @@ +/* Wrapper arpund system calls to provide cancelation points. + Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define __FORCE_GLIBC +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef __PIC__ +/* We need a hook to force this file to be linked in when static + libpthread is used. */ +const int __pthread_provide_wrappers = 0; +#endif + + +#define CANCELABLE_SYSCALL(res_type, name, param_list, params) \ +res_type __libc_##name param_list; \ +res_type \ +__attribute__ ((weak)) \ +name param_list \ +{ \ + res_type result; \ + int oldtype; \ + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); \ + result = __libc_##name params; \ + pthread_setcanceltype (oldtype, NULL); \ + return result; \ +} + +#define CANCELABLE_SYSCALL_VA(res_type, name, param_list, params, last_arg) \ +res_type __libc_##name param_list; \ +res_type \ +__attribute__ ((weak)) \ +name param_list \ +{ \ + res_type result; \ + int oldtype; \ + va_list ap; \ + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); \ + va_start (ap, last_arg); \ + result = __libc_##name params; \ + va_end (ap); \ + pthread_setcanceltype (oldtype, NULL); \ + return result; \ +} + + +/* close(2). */ +CANCELABLE_SYSCALL (int, close, (int fd), (fd)) + + +/* fcntl(2). */ +CANCELABLE_SYSCALL_VA (int, fcntl, (int fd, int cmd, ...), + (fd, cmd, va_arg (ap, long int)), cmd) + + +/* fsync(2). */ +CANCELABLE_SYSCALL (int, fsync, (int fd), (fd)) + + +/* lseek(2). */ +CANCELABLE_SYSCALL (off_t, lseek, (int fd, off_t offset, int whence), + (fd, offset, whence)) + +#ifdef __UCLIBC_HAS_LFS__ +/* lseek64(2). */ +CANCELABLE_SYSCALL (off64_t, lseek64, (int fd, off64_t offset, int whence), + (fd, offset, whence)) +#endif + +/* msync(2). */ +CANCELABLE_SYSCALL (int, msync, (__ptr_t addr, size_t length, int flags), + (addr, length, flags)) + + +/* nanosleep(2). */ +CANCELABLE_SYSCALL (int, nanosleep, (const struct timespec *requested_time, + struct timespec *remaining), + (requested_time, remaining)) + + +/* open(2). */ +CANCELABLE_SYSCALL_VA (int, open, (const char *pathname, int flags, ...), + (pathname, flags, va_arg (ap, mode_t)), flags) + + +#ifdef __UCLIBC_HAS_LFS__ +/* open64(3). */ +CANCELABLE_SYSCALL_VA (int, open64, (const char *pathname, int flags, ...), + (pathname, flags, va_arg (ap, mode_t)), flags) +#endif + +/* pause(2). */ +CANCELABLE_SYSCALL (int, pause, (void), ()) + + +/* Enable this if enabling these in syscalls.c */ +/* pread(3). */ +CANCELABLE_SYSCALL (ssize_t, pread, (int fd, void *buf, size_t count, + off_t offset), + (fd, buf, count, offset)) + + +#if defined __UCLIBC_HAS_LFS__ && defined __NR_pread64 +/* pread64(3). */ +CANCELABLE_SYSCALL (ssize_t, pread64, (int fd, void *buf, size_t count, + off64_t offset), + (fd, buf, count, offset)) +#endif + +/* pwrite(3). */ +CANCELABLE_SYSCALL (ssize_t, pwrite, (int fd, const void *buf, size_t n, + off_t offset), + (fd, buf, n, offset)) + + +#if defined __UCLIBC_HAS_LFS__ && defined __NR_pwrited64 +/* pwrite64(3). */ +CANCELABLE_SYSCALL (ssize_t, pwrite64, (int fd, const void *buf, size_t n, + off64_t offset), + (fd, buf, n, offset)) +#endif + +/* read(2). */ +CANCELABLE_SYSCALL (ssize_t, read, (int fd, void *buf, size_t count), + (fd, buf, count)) + + +/* system(3). */ +CANCELABLE_SYSCALL (int, system, (const char *line), (line)) + + +/* tcdrain(2). */ +CANCELABLE_SYSCALL (int, tcdrain, (int fd), (fd)) + + +/* wait(2). */ +CANCELABLE_SYSCALL (__pid_t, wait, (__WAIT_STATUS_DEFN stat_loc), (stat_loc)) + + +/* waitpid(2). */ +CANCELABLE_SYSCALL (__pid_t, waitpid, (__pid_t pid, int *stat_loc, + int options), + (pid, stat_loc, options)) + + +/* write(2). */ +CANCELABLE_SYSCALL (ssize_t, write, (int fd, const void *buf, size_t n), + (fd, buf, n)) + + +/* The following system calls are thread cancellation points specified + in XNS. */ + +/* accept(2). */ +CANCELABLE_SYSCALL (int, accept, (int fd, __SOCKADDR_ARG addr, + socklen_t *addr_len), + (fd, addr, addr_len)) + +/* connect(2). */ +CANCELABLE_SYSCALL (int, connect, (int fd, __CONST_SOCKADDR_ARG addr, + socklen_t len), + (fd, addr, len)) + +/* recv(2). */ +CANCELABLE_SYSCALL (ssize_t, recv, (int fd, __ptr_t buf, size_t n, int flags), + (fd, buf, n, flags)) + +/* recvfrom(2). */ +CANCELABLE_SYSCALL (ssize_t, recvfrom, (int fd, __ptr_t buf, size_t n, int flags, + __SOCKADDR_ARG addr, socklen_t *addr_len), + (fd, buf, n, flags, addr, addr_len)) + +/* recvmsg(2). */ +CANCELABLE_SYSCALL (ssize_t, recvmsg, (int fd, struct msghdr *message, int flags), + (fd, message, flags)) + +/* send(2). */ +CANCELABLE_SYSCALL (ssize_t, send, (int fd, const __ptr_t buf, size_t n, + int flags), + (fd, buf, n, flags)) + +/* sendmsg(2). */ +CANCELABLE_SYSCALL (ssize_t, sendmsg, (int fd, const struct msghdr *message, + int flags), + (fd, message, flags)) + +/* sendto(2). */ +CANCELABLE_SYSCALL (ssize_t, sendto, (int fd, const __ptr_t buf, size_t n, + int flags, __CONST_SOCKADDR_ARG addr, + socklen_t addr_len), + (fd, buf, n, flags, addr, addr_len)) diff --git a/libpthread/linuxthreads.old_db/Banner b/libpthread/linuxthreads.old_db/Banner new file mode 100644 index 000000000..6f4f3f818 --- /dev/null +++ b/libpthread/linuxthreads.old_db/Banner @@ -0,0 +1 @@ +libthread_db work sponsored by Alpha Processor Inc diff --git a/libpthread/linuxthreads.old_db/Makefile b/libpthread/linuxthreads.old_db/Makefile new file mode 100644 index 000000000..f92f205a5 --- /dev/null +++ b/libpthread/linuxthreads.old_db/Makefile @@ -0,0 +1,15 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +TOPDIR=../../ + +top_srcdir=$(TOPDIR) +top_builddir=../../ +include $(top_builddir)Rules.mak +all: libs +include Makefile.in +include $(top_srcdir)Makerules diff --git a/libpthread/linuxthreads.old_db/Makefile.in b/libpthread/linuxthreads.old_db/Makefile.in new file mode 100644 index 000000000..0e29c7c18 --- /dev/null +++ b/libpthread/linuxthreads.old_db/Makefile.in @@ -0,0 +1,43 @@ +# Makefile for uClibc +# +# Copyright (C) 2000-2005 Erik Andersen +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +#CFLAGS+=$(SSP_ALL_CFLAGS) + +PT_MAJOR_VERSION:=$(MAJOR_VERSION) +# Get the thread include dependencies and shared object name +CFLAGS+=-DLIBPTHREAD_SO="\"libpthread.so.$(PT_MAJOR_VERSION)\"" + +# Remove any -z defs since this lib will have undefined symbols +LDFLAGS:=$(subst -z defs,,$(LDFLAGS)) --warn-unresolved-symbols + +ifeq ($(PTHREADS_DEBUG_SUPPORT),y) +STRIP_FLAGS:=-X --strip-debug -R .note -R .comment +endif + +DOMULTI=n + +LIB_NAME:=libthread_db +libthread_db_FULL_NAME:=$(LIB_NAME)-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so + +MAJOR_VERSION:=1 + +libthread_db_DIR:=$(top_srcdir)libpthread/linuxthreads.old_db +libthread_db_OUT:=$(top_builddir)libpthread/linuxthreads.old_db + +libthread_db_SRC:=$(wildcard $(libthread_db_DIR)/*.c) + +libthread_db_OBJ:=$(patsubst $(libthread_db_DIR)/%.c,$(libthread_db_OUT)/%.o,$(libthread_db_SRC)) + +libthread_db-a-$(PTHREADS_DEBUG_SUPPORT)+=$(libthread_db_OBJ) +libthread_db-so-$(PTHREADS_DEBUG_SUPPORT)+=$(libthread_db_OBJ:.o=.os) + +libthread_db-multi-$(PTHREADS_DEBUG_SUPPORT)+=$(libthread_db_SRC) + +objclean-y+=libthread_db_clean + +lib-a-$(PTHREADS_DEBUG_SUPPORT)+=$(top_builddir)lib/libthread_db.a +lib-so-$(PTHREADS_DEBUG_SUPPORT)+=$(top_builddir)lib/libthread_db.so diff --git a/libpthread/linuxthreads.old_db/Versions b/libpthread/linuxthreads.old_db/Versions new file mode 100644 index 000000000..4ca8042c1 --- /dev/null +++ b/libpthread/linuxthreads.old_db/Versions @@ -0,0 +1,21 @@ +libthread_db { + GLIBC_2.1.3 { + # t* + td_init; td_log; td_ta_clear_event; td_ta_delete; td_ta_enable_stats; + td_ta_event_addr; td_ta_event_getmsg; td_ta_get_nthreads; td_ta_get_ph; + td_ta_get_stats; td_ta_map_id2thr; td_ta_map_lwp2thr; td_ta_new; + td_ta_reset_stats; td_ta_set_event; td_ta_setconcurrency; + td_ta_thr_iter; td_ta_tsd_iter; td_thr_clear_event; td_thr_dbresume; + td_thr_dbsuspend; td_thr_event_enable; td_thr_event_getmsg; + td_thr_get_info; td_thr_getfpregs; td_thr_getgregs; td_thr_getxregs; + td_thr_getxregsize; td_thr_set_event; td_thr_setfpregs; td_thr_setgregs; + td_thr_setprio; td_thr_setsigpending; td_thr_setxregs; td_thr_sigsetmask; + td_thr_tsd; td_thr_validate; + } + GLIBC_2.2.3 { + td_symbol_list; + } + GLIBC_2.3 { + td_thr_tls_get_addr; + } +} diff --git a/libpthread/linuxthreads.old_db/proc_service.h b/libpthread/linuxthreads.old_db/proc_service.h new file mode 100644 index 000000000..74136c03e --- /dev/null +++ b/libpthread/linuxthreads.old_db/proc_service.h @@ -0,0 +1,70 @@ +/* Copyright (C) 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* The definitions in this file must correspond to those in the debugger. */ +#include + +typedef enum +{ + PS_OK, /* generic "call succeeded" */ + PS_ERR, /* generic. */ + PS_BADPID, /* bad process handle */ + PS_BADLID, /* bad lwp identifier */ + PS_BADADDR, /* bad address */ + PS_NOSYM, /* p_lookup() could not find given symbol */ + PS_NOFREGS + /* + * FPU register set not available for given + * lwp + */ +} ps_err_e; + + +struct ps_prochandle; /* user defined. */ + + +extern ps_err_e ps_pdread(struct ps_prochandle *, + psaddr_t, void *, size_t); +extern ps_err_e ps_pdwrite(struct ps_prochandle *, + psaddr_t, const void *, size_t); +extern ps_err_e ps_ptread(struct ps_prochandle *, + psaddr_t, void *, size_t); +extern ps_err_e ps_ptwrite(struct ps_prochandle *, + psaddr_t, const void *, size_t); + +extern ps_err_e ps_pglobal_lookup(struct ps_prochandle *, + const char *object_name, const char *sym_name, psaddr_t *sym_addr); + + +extern ps_err_e ps_lgetregs(struct ps_prochandle *, + lwpid_t, prgregset_t); +extern ps_err_e ps_lsetregs(struct ps_prochandle *, + lwpid_t, const prgregset_t); +extern ps_err_e ps_lgetfpregs(struct ps_prochandle *, + lwpid_t, prfpregset_t *); +extern ps_err_e ps_lsetfpregs(struct ps_prochandle *, + lwpid_t, const prfpregset_t *); + +extern pid_t ps_getpid (struct ps_prochandle *); + + +extern ps_err_e ps_pstop (const struct ps_prochandle *); +extern ps_err_e ps_pcontinue (const struct ps_prochandle *); + +extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t); +extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t); diff --git a/libpthread/linuxthreads.old_db/td_init.c b/libpthread/linuxthreads.old_db/td_init.c new file mode 100644 index 000000000..d714f1ba0 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_init.c @@ -0,0 +1,32 @@ +/* Initialization function of thread debugger support library. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +int __td_debug; + + +td_err_e +td_init (void) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_init"); + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_log.c b/libpthread/linuxthreads.old_db/td_log.c new file mode 100644 index 000000000..025273a63 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_log.c @@ -0,0 +1,32 @@ +/* Noop, left for historical reasons. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_log (void) +{ + /* This interface is deprecated in the Sun interface. We provide it + for compatibility but don't do anything ourself. We might in + future do some logging if this seems reasonable. */ + LOG ("td_log"); + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_symbol_list.c b/libpthread/linuxthreads.old_db/td_symbol_list.c new file mode 100644 index 000000000..779332b9d --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_symbol_list.c @@ -0,0 +1,56 @@ +/* Return list of symbols the library can request. + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2001. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include "thread_dbP.h" + + +static const char *symbol_list_arr[] = +{ + [PTHREAD_THREADS_EVENTS] = "__pthread_threads_events", + [PTHREAD_LAST_EVENT] = "__pthread_last_event", + [PTHREAD_HANDLES_NUM] = "__pthread_handles_num", + [PTHREAD_HANDLES] = "__pthread_handles", + [PTHREAD_KEYS] = "pthread_keys", + [LINUXTHREADS_PTHREAD_THREADS_MAX] = "__linuxthreads_pthread_threads_max", + [LINUXTHREADS_PTHREAD_KEYS_MAX] = "__linuxthreads_pthread_keys_max", + [LINUXTHREADS_PTHREAD_SIZEOF_DESCR] = "__linuxthreads_pthread_sizeof_descr", + [LINUXTHREADS_CREATE_EVENT] = "__linuxthreads_create_event", + [LINUXTHREADS_DEATH_EVENT] = "__linuxthreads_death_event", + [LINUXTHREADS_REAP_EVENT] = "__linuxthreads_reap_event", + [LINUXTHREADS_INITIAL_REPORT_EVENTS] = "__linuxthreads_initial_report_events", + [LINUXTHREADS_VERSION] = "__linuxthreads_version", + [NUM_MESSAGES] = NULL +}; + + +const char ** +td_symbol_list (void) +{ + return symbol_list_arr; +} + + +int +td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr) +{ + assert (idx >= 0 && idx < NUM_MESSAGES); + return ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], sym_addr); +} diff --git a/libpthread/linuxthreads.old_db/td_ta_clear_event.c b/libpthread/linuxthreads.old_db/td_ta_clear_event.c new file mode 100644 index 000000000..bdbcf47aa --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_clear_event.c @@ -0,0 +1,53 @@ +/* Globally disable events. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_clear_event (ta, event) + const td_thragent_t *ta; + td_thr_events_t *event; +{ + td_thr_events_t old_event; + int i; + + LOG ("td_ta_clear_event"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Write the new value into the thread data structure. */ + if (ps_pdread (ta->ph, ta->pthread_threads_eventsp, + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Remove the set bits in. */ + for (i = 0; i < TD_EVENTSIZE; ++i) + old_event.event_bits[i] &= ~event->event_bits[i]; + + /* Write the new value into the thread data structure. */ + if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp, + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_delete.c b/libpthread/linuxthreads.old_db/td_ta_delete.c new file mode 100644 index 000000000..0e6ec17d0 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_delete.c @@ -0,0 +1,58 @@ +/* Detach to target process. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#include "thread_dbP.h" + + +td_err_e +td_ta_delete (td_thragent_t *ta) +{ + LOG ("td_ta_delete"); + + /* Safety check. */ + if (ta == NULL || __td_agent_list == NULL) + return TD_BADTA; + + /* Remove the handle from the list. */ + if (ta == __td_agent_list->ta) + /* It's the first element of the list. */ + __td_agent_list = __td_agent_list->next; + else + { + /* We have to search for it. */ + struct agent_list *runp = __td_agent_list; + + while (runp->next != NULL && runp->next->ta != ta) + runp = runp->next; + + if (runp->next == NULL) + /* It's not a valid decriptor since it is not in the list. */ + return TD_BADTA; + + runp->next = runp->next->next; + } + + /* The handle was allocated in `td_ta_new'. */ + free (ta); + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_enable_stats.c b/libpthread/linuxthreads.old_db/td_ta_enable_stats.c new file mode 100644 index 000000000..1d4c34a8d --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_enable_stats.c @@ -0,0 +1,35 @@ +/* Enable collection of statistics for process. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_enable_stats (const td_thragent_t *ta, int enable) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_enable_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_event_addr.c b/libpthread/linuxthreads.old_db/td_ta_event_addr.c new file mode 100644 index 000000000..8bce35ae8 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_event_addr.c @@ -0,0 +1,73 @@ +/* Get event address. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_event_addr (const td_thragent_t *ta, td_event_e event, td_notify_t *addr) +{ + td_err_e res = TD_NOEVENT; + int idx = -1; + + LOG ("td_ta_event_addr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + switch (event) + { + case TD_CREATE: + idx = LINUXTHREADS_CREATE_EVENT; + break; + + case TD_DEATH: + idx = LINUXTHREADS_DEATH_EVENT; + break; + + case TD_REAP: + idx = LINUXTHREADS_REAP_EVENT; + break; + + default: + /* Event cannot be handled. */ + break; + } + + /* Now get the address. */ + if (idx != -1) + { + psaddr_t taddr; + + if (td_lookup (ta->ph, idx, &taddr) == PS_OK) + { + /* Success, we got the address. */ + addr->type = NOTIFY_BPT; + addr->u.bptaddr = taddr; + + res = TD_OK; + } + else + res = TD_ERR; + } + + return res; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_event_getmsg.c b/libpthread/linuxthreads.old_db/td_ta_event_getmsg.c new file mode 100644 index 000000000..c004a5b79 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_event_getmsg.c @@ -0,0 +1,129 @@ +/* Retrieve event. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#include "thread_dbP.h" +#include "../linuxthreads.old/internals.h" + + +td_err_e +td_ta_event_getmsg (const td_thragent_t *ta, td_event_msg_t *msg) +{ + /* XXX I cannot think of another way but using a static variable. */ + static td_thrhandle_t th; + td_eventbuf_t event; + psaddr_t addr; + + LOG ("td_ta_event_getmsg"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Get the pointer to the thread descriptor with the last event. */ + if (ps_pdread (ta->ph, ta->pthread_last_event, + &addr, sizeof (void *)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* If the pointer is NULL no event occurred. */ + if (addr == 0) + return TD_NOMSG; + + /* Read the even structure from the target. */ + if (ps_pdread (ta->ph, + ((char *) addr + + offsetof (struct _pthread_descr_struct, p_eventbuf)), + &event, sizeof (td_eventbuf_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Check whether an event occurred. */ + if (event.eventnum == TD_EVENT_NONE) + { + /* Oh well, this means the last event was already read. So + we have to look for any other event. */ + struct pthread_handle_struct handles[ta->pthread_threads_max]; + int num; + int i; + + /* Read the number of currently active threads. */ + if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) + != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Now read the handles. */ + if (ps_pdread (ta->ph, ta->handles, handles, + ta->pthread_threads_max * sizeof (handles[0])) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + for (i = 0; i < ta->pthread_threads_max && num > 0; ++i) + { + if (handles[i].h_descr == NULL) + /* No entry here. */ + continue; + + /* First count this active thread. */ + --num; + + if (handles[i].h_descr == addr) + /* We already handled this. */ + continue; + + /* Read the event data for this thread. */ + if (ps_pdread (ta->ph, + ((char *) handles[i].h_descr + + offsetof (struct _pthread_descr_struct, + p_eventbuf)), + &event, sizeof (td_eventbuf_t)) != PS_OK) + return TD_ERR; + + if (event.eventnum != TD_EVENT_NONE) + { + /* We found a thread with an unreported event. */ + addr = handles[i].h_descr; + break; + } + } + + /* If we haven't found any other event signal this to the user. */ + if (event.eventnum == TD_EVENT_NONE) + return TD_NOMSG; + } + + /* Generate the thread descriptor. */ + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = addr; + + /* Fill the user's data structure. */ + msg->event = event.eventnum; + msg->th_p = &th; + msg->msg.data = (uintptr_t) event.eventdata; + + /* And clear the event message in the target. */ + memset (&event, '\0', sizeof (td_eventbuf_t)); + if (ps_pdwrite (ta->ph, + ((char *) addr + + offsetof (struct _pthread_descr_struct, p_eventbuf)), + &event, sizeof (td_eventbuf_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_get_nthreads.c b/libpthread/linuxthreads.old_db/td_ta_get_nthreads.c new file mode 100644 index 000000000..839b56be5 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_get_nthreads.c @@ -0,0 +1,42 @@ +/* Get the number of threads in the process. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + +td_err_e +td_ta_get_nthreads (const td_thragent_t *ta, int *np) +{ + psaddr_t addr; + + LOG ("td_ta_get_nthreads"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Access the variable `__pthread_handles_num'. */ + if (td_lookup (ta->ph, PTHREAD_HANDLES_NUM, &addr) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + if (ps_pdread (ta->ph, addr, np, sizeof (int)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_get_ph.c b/libpthread/linuxthreads.old_db/td_ta_get_ph.c new file mode 100644 index 000000000..23d328508 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_get_ph.c @@ -0,0 +1,36 @@ +/* Get external process handle. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph) +{ + LOG ("td_ta_get_ph"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + *ph = ta->ph; + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_get_stats.c b/libpthread/linuxthreads.old_db/td_ta_get_stats.c new file mode 100644 index 000000000..6bf2f5352 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_get_stats.c @@ -0,0 +1,35 @@ +/* Retrieve statistics for process. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_get_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_map_id2thr.c b/libpthread/linuxthreads.old_db/td_ta_map_id2thr.c new file mode 100644 index 000000000..30f272af6 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_map_id2thr.c @@ -0,0 +1,79 @@ +/* Map thread ID to thread handle. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include "../linuxthreads.old/internals.h" + + +td_err_e +td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th) +{ + struct pthread_handle_struct phc; + struct _pthread_descr_struct pds; + int pthread_threads_max; + + LOG ("td_ta_map_id2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Make the following expression a bit smaller. */ + pthread_threads_max = ta->pthread_threads_max; + + /* We can compute the entry in the handle array we want. */ + if (ps_pdread (ta->ph, ta->handles + pt % pthread_threads_max, &phc, + sizeof (struct pthread_handle_struct)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Test whether this entry is in use. */ + if (phc.h_descr == NULL) + { + if (pt % pthread_threads_max == 0) + { + /* The initial thread always exists but the thread library + might not yet be initialized. */ + th->th_ta_p = (td_thragent_t *) ta; + th->th_unique = NULL; + + return TD_OK; + } + + return TD_BADTH; + } + + /* Next test: get the descriptor to see whether this is not an old + thread handle. */ + if (ps_pdread (ta->ph, phc.h_descr, &pds, + sizeof (struct _pthread_descr_struct)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + if (pds.p_tid != pt) + return TD_BADTH; + + if (pds.p_terminated != 0) + return TD_NOTHR; + + /* Create the `td_thrhandle_t' object. */ + th->th_ta_p = (td_thragent_t *) ta; + th->th_unique = phc.h_descr; + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_map_lwp2thr.c b/libpthread/linuxthreads.old_db/td_ta_map_lwp2thr.c new file mode 100644 index 000000000..5bdf970e4 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_map_lwp2thr.c @@ -0,0 +1,91 @@ +/* Which thread is running on an lwp? + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include "../linuxthreads.old/internals.h" + + +td_err_e +td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th) +{ + int pthread_threads_max = ta->pthread_threads_max; + size_t sizeof_descr = ta->sizeof_descr; + struct pthread_handle_struct phc[pthread_threads_max]; + size_t cnt; +#ifdef ALL_THREADS_STOPPED + int num; +#else +# define num 1 +#endif + + LOG ("td_ta_map_lwp2thr"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Read all the descriptors. */ + if (ps_pdread (ta->ph, ta->handles, phc, + sizeof (struct pthread_handle_struct) * pthread_threads_max) + != PS_OK) + return TD_ERR; /* XXX Other error value? */ + +#ifdef ALL_THREADS_STOPPED + /* Read the number of currently active threads. */ + if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ +#endif + + /* Get the entries one after the other and find out whether the ID + matches. */ + for (cnt = 0; cnt < pthread_threads_max && num > 0; ++cnt) + if (phc[cnt].h_descr != NULL) + { + struct _pthread_descr_struct pds; + +#ifdef ALL_THREADS_STOPPED + /* First count this active thread. */ + --num; +#endif + + if (ps_pdread (ta->ph, phc[cnt].h_descr, &pds, sizeof_descr) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + if ((pds.p_pid ?: ps_getpid (ta->ph)) == lwpid) + { + /* Found it. Now fill in the `td_thrhandle_t' object. */ + th->th_ta_p = (td_thragent_t *) ta; + th->th_unique = phc[cnt].h_descr; + + return TD_OK; + } + } + else if (cnt == 0) + { + /* The initial thread always exists. But it might not yet be + initialized. Construct a value. */ + th->th_ta_p = (td_thragent_t *) ta; + th->th_unique = NULL; + + return TD_OK; + } + + return TD_NOLWP; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_new.c b/libpthread/linuxthreads.old_db/td_ta_new.c new file mode 100644 index 000000000..9bf926719 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_new.c @@ -0,0 +1,150 @@ +/* Attach to target process. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +#include "thread_dbP.h" + + +/* Datatype for the list of known thread agents. Normally there will + be exactly one so we don't spend much though on making it fast. */ +struct agent_list *__td_agent_list; + + +td_err_e +td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) +{ + psaddr_t addr; + psaddr_t versaddr; + char versbuf[sizeof (VERSION)]; + struct agent_list *elemp; + + LOG ("td_ta_new"); + + /* Get the global event mask. This is one of the variables which + are new in the thread library to enable debugging. If it is + not available we cannot debug. */ + if (td_lookup (ps, PTHREAD_THREADS_EVENTS, &addr) != PS_OK) + return TD_NOLIBTHREAD; + + /* Check whether the versions match. */ + if (td_lookup (ps, LINUXTHREADS_VERSION, &versaddr) != PS_OK) + return TD_VERSION; + if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK) + return TD_ERR; + + versbuf[sizeof (versbuf) - 1] = '\0'; + if (strcmp (versbuf, VERSION) != 0) + /* Not the right version. */ + return TD_VERSION; + + /* Fill in the appropriate information. */ + *ta = (td_thragent_t *) malloc (sizeof (td_thragent_t)); + if (*ta == NULL) + return TD_MALLOC; + + /* Store the proc handle which we will pass to the callback functions + back into the debugger. */ + (*ta)->ph = ps; + + /* Remember the address. */ + (*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr; + + /* Get the pointer to the variable pointing to the thread descriptor + with the last event. */ + if (td_lookup (ps, PTHREAD_LAST_EVENT, &(*ta)->pthread_last_event) != PS_OK) + { + free_return: + free (*ta); + return TD_ERR; + } + + /* Get the pointer to the variable containing the number of active + threads. */ + if (td_lookup (ps, PTHREAD_HANDLES_NUM, &(*ta)->pthread_handles_num) + != PS_OK) + goto free_return; + + /* See whether the library contains the necessary symbols. */ + if (td_lookup (ps, PTHREAD_HANDLES, &addr) != PS_OK) + goto free_return; + + (*ta)->handles = (struct pthread_handle_struct *) addr; + + + if (td_lookup (ps, PTHREAD_KEYS, &addr) != PS_OK) + goto free_return; + + /* Cast to the right type. */ + (*ta)->keys = (struct pthread_key_struct *) addr; + + /* Find out about the maximum number of threads. Old implementations + don't provide this information. In this case we assume that the + debug library is compiled with the same values. */ + if (td_lookup (ps, LINUXTHREADS_PTHREAD_THREADS_MAX, &addr) != PS_OK) + (*ta)->pthread_threads_max = PTHREAD_THREADS_MAX; + else + { + if (ps_pdread (ps, addr, &(*ta)->pthread_threads_max, sizeof (int)) + != PS_OK) + goto free_return; + } + + /* Similar for the maximum number of thread local data keys. */ + if (td_lookup (ps, LINUXTHREADS_PTHREAD_KEYS_MAX, &addr) != PS_OK) + (*ta)->pthread_keys_max = PTHREAD_KEYS_MAX; + else + { + if (ps_pdread (ps, addr, &(*ta)->pthread_keys_max, sizeof (int)) + != PS_OK) + goto free_return; + } + + /* And for the size of the second level arrays for the keys. */ + if (td_lookup (ps, LINUXTHREADS_PTHREAD_SIZEOF_DESCR, &addr) != PS_OK) + (*ta)->sizeof_descr = sizeof (struct _pthread_descr_struct); + else + { + if (ps_pdread (ps, addr, &(*ta)->sizeof_descr, sizeof (int)) != PS_OK) + goto free_return; + /* Don't let bogons in the inferior make us mess ourselves. */ + if ((*ta)->sizeof_descr > sizeof (struct _pthread_descr_struct)) + (*ta)->sizeof_descr = sizeof (struct _pthread_descr_struct); + + } + + /* Now add the new agent descriptor to the list. */ + elemp = (struct agent_list *) malloc (sizeof (struct agent_list)); + if (elemp == NULL) + { + /* Argh, now that everything else worked... */ + free (*ta); + return TD_MALLOC; + } + + /* We don't care for thread-safety here. */ + elemp->ta = *ta; + elemp->next = __td_agent_list; + __td_agent_list = elemp; + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_reset_stats.c b/libpthread/linuxthreads.old_db/td_ta_reset_stats.c new file mode 100644 index 000000000..b3ddbd07b --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_reset_stats.c @@ -0,0 +1,35 @@ +/* Reset statistics. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_reset_stats (const td_thragent_t *ta) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_ta_reset_stats"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_set_event.c b/libpthread/linuxthreads.old_db/td_ta_set_event.c new file mode 100644 index 000000000..73cf9f405 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_set_event.c @@ -0,0 +1,53 @@ +/* Globally enable events. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_set_event (ta, event) + const td_thragent_t *ta; + td_thr_events_t *event; +{ + td_thr_events_t old_event; + int i; + + LOG ("td_ta_set_event"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + /* Write the new value into the thread data structure. */ + if (ps_pdread (ta->ph, ta->pthread_threads_eventsp, + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Or the new bits in. */ + for (i = 0; i < TD_EVENTSIZE; ++i) + old_event.event_bits[i] |= event->event_bits[i]; + + /* Write the new value into the thread data structure. */ + if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp, + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_setconcurrency.c b/libpthread/linuxthreads.old_db/td_ta_setconcurrency.c new file mode 100644 index 000000000..408e76309 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_setconcurrency.c @@ -0,0 +1,35 @@ +/* Set suggested concurrency level for process. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_ta_setconcurrency (const td_thragent_t *ta, int level) +{ + /* This is something LinuxThreads does not support. */ + LOG ("td_ta_setconcurrency"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + return TD_NOCAPAB; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_thr_iter.c b/libpthread/linuxthreads.old_db/td_ta_thr_iter.c new file mode 100644 index 000000000..6cc4bf7c1 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_thr_iter.c @@ -0,0 +1,174 @@ +/* Iterate over a process's threads. + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include "../linuxthreads.old/internals.h" +#include + +static int +handle_descr (const td_thragent_t *ta, td_thr_iter_f *callback, + void *cbdata_p, td_thr_state_e state, int ti_pri, + size_t cnt, pthread_descr descr) +{ + struct _pthread_descr_struct pds; + size_t sizeof_descr = ta->sizeof_descr; + td_thrhandle_t th; + + if (descr == NULL) + { + /* No descriptor (yet). */ + if (cnt == 0) + { + /* This is the main thread. Create a fake descriptor. */ + memset (&pds, '\0', sizeof (pds)); + + /* Empty thread descriptor the thread library would create. */ + pds.p_self = &pds; + pds.p_nextlive = pds.p_prevlive = &pds; + pds.p_tid = PTHREAD_THREADS_MAX; + /* The init code also sets up p_lock, p_errnop, p_herrnop, and + p_userstack but this should not be necessary here. */ + + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = NULL; + if (callback (&th, cbdata_p) != 0) + return TD_DBERR; + + /* All done successfully. */ + return TD_OK; + } + else if (cnt == 1) + /* The manager is not yet started. No big deal. */ + return TD_OK; + else + /* For every other thread this should not happen. */ + return TD_ERR; + } + + if (ps_pdread (ta->ph, descr, &pds, sizeof_descr) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* The manager thread must be handled special. The descriptor + exists but the thread only gets created when the first + `pthread_create' call is issued. A clear indication that this + happened is when the p_pid field is non-zero. */ + if (cnt == 1 && pds.p_pid == 0) + return TD_OK; + + /* Now test whether this thread matches the specified + conditions. */ + + /* Only if the priority level is as high or higher. */ + if (pds.p_priority < ti_pri) + return TD_OK; + + /* Test the state. + XXX This is incomplete. */ + if (state != TD_THR_ANY_STATE) + return TD_OK; + + /* XXX For now we ignore threads which are not running anymore. + The reason is that gdb tries to get the registers and fails. + In future we should have a special mode of the thread library + in which we keep the process around until the actual join + operation happened. */ + if (pds.p_exited != 0) + return TD_OK; + + /* Yep, it matches. Call the callback function. */ + th.th_ta_p = (td_thragent_t *) ta; + th.th_unique = descr; + if (callback (&th, cbdata_p) != 0) + return TD_DBERR; + + /* All done successfully. */ + return TD_OK; +} + + +td_err_e +td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback, + void *cbdata_p, td_thr_state_e state, int ti_pri, + sigset_t *ti_sigmask_p, unsigned int ti_user_flags) +{ + int pthread_threads_max; + struct pthread_handle_struct *phc; + td_err_e result = TD_OK; + int cnt; +#ifdef ALL_THREADS_STOPPED + int num; +#else +# define num 1 +#endif + + LOG ("td_ta_thr_iter"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + pthread_threads_max = ta->pthread_threads_max; + phc = (struct pthread_handle_struct *) alloca (sizeof (phc[0]) + * pthread_threads_max); + + /* First read only the main thread and manager thread information. */ + if (ps_pdread (ta->ph, ta->handles, phc, + sizeof (struct pthread_handle_struct) * 2) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Now handle these descriptors. */ + result = handle_descr (ta, callback, cbdata_p, state, ti_pri, 0, + phc[0].h_descr); + if (result != TD_OK) + return result; + result = handle_descr (ta, callback, cbdata_p, state, ti_pri, 1, + phc[1].h_descr); + if (result != TD_OK) + return result; + + /* Read all the descriptors. */ + if (ps_pdread (ta->ph, ta->handles + 2, &phc[2], + (sizeof (struct pthread_handle_struct) + * (pthread_threads_max - 2))) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + +#ifdef ALL_THREADS_STOPPED + /* Read the number of currently active threads. */ + if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ +#endif + + /* Now get all descriptors, one after the other. */ + for (cnt = 2; cnt < pthread_threads_max && num > 0; ++cnt) + if (phc[cnt].h_descr != NULL) + { +#ifdef ALL_THREADS_STOPPED + /* First count this active thread. */ + --num; +#endif + + result = handle_descr (ta, callback, cbdata_p, state, ti_pri, cnt, + phc[cnt].h_descr); + if (result != TD_OK) + break; + } + + return result; +} diff --git a/libpthread/linuxthreads.old_db/td_ta_tsd_iter.c b/libpthread/linuxthreads.old_db/td_ta_tsd_iter.c new file mode 100644 index 000000000..f15b45003 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_ta_tsd_iter.c @@ -0,0 +1,56 @@ +/* Iterate over a process's thread-specific data. + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include "../linuxthreads.old/internals.h" +#include + +td_err_e +td_ta_tsd_iter (const td_thragent_t *ta, td_key_iter_f *callback, + void *cbdata_p) +{ + struct pthread_key_struct *keys; + int pthread_keys_max; + int cnt; + + LOG ("td_ta_tsd_iter"); + + /* Test whether the TA parameter is ok. */ + if (! ta_ok (ta)) + return TD_BADTA; + + pthread_keys_max = ta->pthread_keys_max; + keys = (struct pthread_key_struct *) alloca (sizeof (keys[0]) + * pthread_keys_max); + + /* Read all the information about the keys. */ + if (ps_pdread (ta->ph, ta->keys, keys, + sizeof (keys[0]) * pthread_keys_max) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Now get all descriptors, one after the other. */ + for (cnt = 0; cnt < pthread_keys_max; ++cnt) + if (keys[cnt].in_use + /* Return with an error if the callback returns a nonzero value. */ + && callback (cnt, keys[cnt].destr, cbdata_p) != 0) + return TD_DBERR; + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_clear_event.c b/libpthread/linuxthreads.old_db/td_thr_clear_event.c new file mode 100644 index 000000000..c027fc09f --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_clear_event.c @@ -0,0 +1,62 @@ +/* Disable specific event for thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#include "thread_dbP.h" + + +td_err_e +td_thr_clear_event (th, event) + const td_thrhandle_t *th; + td_thr_events_t *event; +{ + td_thr_events_t old_event; + int i; + + LOG ("td_thr_clear_event"); + + /* If the thread descriptor has not yet been constructed do not do + anything. */ + if (th->th_unique == NULL) + return TD_OK; + + /* Write the new value into the thread data structure. */ + if (ps_pdread (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, + p_eventbuf.eventmask)), + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Remove the set bits in. */ + for (i = 0; i < TD_EVENTSIZE; ++i) + old_event.event_bits[i] &= ~event->event_bits[i]; + + /* Write the new value into the thread data structure. */ + if (ps_pdwrite (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, + p_eventbuf.eventmask)), + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_dbresume.c b/libpthread/linuxthreads.old_db/td_thr_dbresume.c new file mode 100644 index 000000000..7b7f6eef9 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_dbresume.c @@ -0,0 +1,30 @@ +/* Resume execution of given thread. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_dbresume (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbresume"); + return TD_NOCAPAB; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_dbsuspend.c b/libpthread/linuxthreads.old_db/td_thr_dbsuspend.c new file mode 100644 index 000000000..ef668023d --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_dbsuspend.c @@ -0,0 +1,30 @@ +/* Suspend execution of given thread. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_dbsuspend (const td_thrhandle_t *th) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_dbsuspend"); + return TD_NOCAPAB; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_event_enable.c b/libpthread/linuxthreads.old_db/td_thr_event_enable.c new file mode 100644 index 000000000..407f3fc44 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_event_enable.c @@ -0,0 +1,57 @@ +/* Enable event process-wide. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#include "thread_dbP.h" + + +td_err_e +td_thr_event_enable (th, onoff) + const td_thrhandle_t *th; + int onoff; +{ + LOG ("td_thr_event_enable"); + + /* Write the new value into the thread data structure. */ + if (th->th_unique == NULL) + { + psaddr_t addr; + + if (td_lookup (th->th_ta_p->ph, LINUXTHREADS_INITIAL_REPORT_EVENTS, + &addr) != PS_OK) + /* Cannot read the symbol. This should not happen. */ + return TD_ERR; + + if (ps_pdwrite (th->th_ta_p->ph, addr, &onoff, sizeof (int)) != PS_OK) + return TD_ERR; + + return TD_OK; + } + + if (ps_pdwrite (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, + p_report_events)), + &onoff, sizeof (int)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_event_getmsg.c b/libpthread/linuxthreads.old_db/td_thr_event_getmsg.c new file mode 100644 index 000000000..bf4ddd4ad --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_event_getmsg.c @@ -0,0 +1,65 @@ +/* Retrieve event. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#include "thread_dbP.h" + + +td_err_e +td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg) +{ + td_eventbuf_t event; + + LOG ("td_thr_event_getmsg"); + + /* If the thread descriptor has not yet been created there cannot be + any event. */ + if (th->th_unique == NULL) + return TD_NOMSG; + + /* Read the even structure from the target. */ + if (ps_pdread (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, p_eventbuf)), + &event, sizeof (td_eventbuf_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Check whether an event occurred. */ + if (event.eventnum == TD_EVENT_NONE) + /* Nothing. */ + return TD_NOMSG; + + /* Fill the user's data structure. */ + msg->event = event.eventnum; + msg->th_p = th; + msg->msg.data = (uintptr_t) event.eventdata; + + /* And clear the event message in the target. */ + memset (&event, '\0', sizeof (td_eventbuf_t)); + if (ps_pdwrite (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, p_eventbuf)), + &event, sizeof (td_eventbuf_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_get_info.c b/libpthread/linuxthreads.old_db/td_thr_get_info.c new file mode 100644 index 000000000..4666bda97 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_get_info.c @@ -0,0 +1,83 @@ +/* Get thread information. + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#include "thread_dbP.h" + + +td_err_e +td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop) +{ + struct _pthread_descr_struct pds; + + LOG ("td_thr_get_info"); + + /* Handle the case when the thread library is not yet initialized. */ + if (th->th_unique == NULL) + { + memset (&pds, '\0', sizeof (pds)); + pds.p_tid = PTHREAD_THREADS_MAX; + } + else + /* Get the thread descriptor. */ + if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, + th->th_ta_p->sizeof_descr) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Fill in information. Clear first to provide reproducable + results for the fields we do not fill in. */ + memset (infop, '\0', sizeof (td_thrinfo_t)); + + /* We have to handle the manager thread special since the thread + descriptor in older versions is not fully initialized. */ + if (pds.p_nr == 1) + { + infop->ti_tid = th->th_ta_p->pthread_threads_max * 2 + 1; + infop->ti_type = TD_THR_SYSTEM; + infop->ti_state = TD_THR_ACTIVE; + } + else + { + infop->ti_tid = pds.p_tid; + infop->ti_tls = (char *) pds.p_specific; + infop->ti_pri = pds.p_priority; + infop->ti_type = TD_THR_USER; + + if (! pds.p_terminated) + /* XXX For now there is no way to get more information. */ + infop->ti_state = TD_THR_ACTIVE; + else if (! pds.p_detached) + infop->ti_state = TD_THR_ZOMBIE; + else + infop->ti_state = TD_THR_UNKNOWN; + } + + /* Initialization which are the same in both cases. */ + infop->ti_lid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); + infop->ti_ta_p = th->th_ta_p; + infop->ti_startfunc = pds.p_start_args.start_routine; + memcpy (&infop->ti_events, &pds.p_eventbuf.eventmask, + sizeof (td_thr_events_t)); + infop->ti_traceme = pds.p_report_events != 0; + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_getfpregs.c b/libpthread/linuxthreads.old_db/td_thr_getfpregs.c new file mode 100644 index 000000000..31c55c876 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_getfpregs.c @@ -0,0 +1,58 @@ +/* Get a thread's floating-point register set. + Copyright (C) 1999, 2001, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset) +{ + struct _pthread_descr_struct pds; + + LOG ("td_thr_getfpregs"); + + if (th->th_unique == NULL) + { + /* No data yet. Use the main thread. */ + pid_t pid = ps_getpid (th->th_ta_p->ph); + if (ps_lgetfpregs (th->th_ta_p->ph, pid, regset) != PS_OK) + return TD_ERR; + return TD_OK; + } + + /* We have to get the state and the PID for this thread. */ + if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, + sizeof (struct _pthread_descr_struct)) != PS_OK) + return TD_ERR; + + /* If the thread already terminated we return all zeroes. */ + if (pds.p_terminated) + memset (regset, '\0', sizeof (*regset)); + /* Otherwise get the register content through the callback. */ + else + { + pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); + + if (ps_lgetfpregs (th->th_ta_p->ph, pid, regset) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_getgregs.c b/libpthread/linuxthreads.old_db/td_thr_getgregs.c new file mode 100644 index 000000000..a9ec6a37d --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_getgregs.c @@ -0,0 +1,58 @@ +/* Get a thread's general register set. + Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getgregs (const td_thrhandle_t *th, prgregset_t gregs) +{ + struct _pthread_descr_struct pds; + + LOG ("td_thr_getgregs"); + + if (th->th_unique == NULL) + { + /* No data yet. Use the main thread. */ + pid_t pid = ps_getpid (th->th_ta_p->ph); + if (ps_lgetregs (th->th_ta_p->ph, pid, gregs) != PS_OK) + return TD_ERR; + return TD_OK; + } + + /* We have to get the state and the PID for this thread. */ + if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, + sizeof (struct _pthread_descr_struct)) != PS_OK) + return TD_ERR; + + /* If the thread already terminated we return all zeroes. */ + if (pds.p_terminated) + memset (gregs, '\0', sizeof (prgregset_t)); + /* Otherwise get the register content through the callback. */ + else + { + pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); + + if (ps_lgetregs (th->th_ta_p->ph, pid, gregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_getxregs.c b/libpthread/linuxthreads.old_db/td_thr_getxregs.c new file mode 100644 index 000000000..39cd73cf1 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_getxregs.c @@ -0,0 +1,30 @@ +/* Get a thread's extra state register set. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getxregs (const td_thrhandle_t *th, void *xregs) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregs"); + return TD_NOXREGS; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_getxregsize.c b/libpthread/linuxthreads.old_db/td_thr_getxregsize.c new file mode 100644 index 000000000..5d8ac288e --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_getxregsize.c @@ -0,0 +1,30 @@ +/* Get the size of the extra state register set for this architecture. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_getxregsize (const td_thrhandle_t *th, int *sizep) +{ + /* XXX This might be platform specific. */ + LOG ("td_thr_getxregsize"); + return TD_NOXREGS; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_set_event.c b/libpthread/linuxthreads.old_db/td_thr_set_event.c new file mode 100644 index 000000000..205b445c7 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_set_event.c @@ -0,0 +1,62 @@ +/* Enable specific event for thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +#include "thread_dbP.h" + + +td_err_e +td_thr_set_event (th, event) + const td_thrhandle_t *th; + td_thr_events_t *event; +{ + td_thr_events_t old_event; + int i; + + LOG ("td_thr_set_event"); + + /* What shall we do if no thread descriptor exists but the user + wants to set an event? */ + if (th->th_unique == NULL) + return TD_NOTALLOC; + + /* Write the new value into the thread data structure. */ + if (ps_pdread (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, + p_eventbuf.eventmask)), + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Or the new bits in. */ + for (i = 0; i < TD_EVENTSIZE; ++i) + old_event.event_bits[i] |= event->event_bits[i]; + + /* Write the new value into the thread data structure. */ + if (ps_pdwrite (th->th_ta_p->ph, + ((char *) th->th_unique + + offsetof (struct _pthread_descr_struct, + p_eventbuf.eventmask)), + &old_event, sizeof (td_thrhandle_t)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_setfpregs.c b/libpthread/linuxthreads.old_db/td_thr_setfpregs.c new file mode 100644 index 000000000..e4d9ec65e --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_setfpregs.c @@ -0,0 +1,47 @@ +/* Set a thread's floating-point register set. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs) +{ + struct _pthread_descr_struct pds = { .p_terminated = 0, .p_pid = 0 }; + + LOG ("td_thr_setfpregs"); + + /* We have to get the state and the PID for this thread. */ + if (th->th_unique != NULL + && ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, + sizeof (struct _pthread_descr_struct)) != PS_OK) + return TD_ERR; + + /* Only set the registers if the thread hasn't yet terminated. */ + if (pds.p_terminated == 0) + { + pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); + + if (ps_lsetfpregs (th->th_ta_p->ph, pid, fpregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_setgregs.c b/libpthread/linuxthreads.old_db/td_thr_setgregs.c new file mode 100644 index 000000000..8c021a473 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_setgregs.c @@ -0,0 +1,47 @@ +/* Set a thread's general register set. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs) +{ + struct _pthread_descr_struct pds = { .p_terminated = 0, .p_pid = 0 }; + + LOG ("td_thr_setgregs"); + + /* We have to get the state and the PID for this thread. */ + if (th->th_unique != NULL + && ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, + sizeof (struct _pthread_descr_struct)) != PS_OK) + return TD_ERR; + + /* Only set the registers if the thread hasn't yet terminated. */ + if (pds.p_terminated == 0) + { + pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); + + if (ps_lsetregs (th->th_ta_p->ph, pid, gregs) != PS_OK) + return TD_ERR; + } + + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_setprio.c b/libpthread/linuxthreads.old_db/td_thr_setprio.c new file mode 100644 index 000000000..98d202dfe --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_setprio.c @@ -0,0 +1,30 @@ +/* Set a thread's priority. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setprio (const td_thrhandle_t *th, int prio) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setprio"); + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_setsigpending.c b/libpthread/linuxthreads.old_db/td_thr_setsigpending.c new file mode 100644 index 000000000..98e30140e --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_setsigpending.c @@ -0,0 +1,31 @@ +/* Raise a signal for a thread. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setsigpending (const td_thrhandle_t *th, unsigned char n, + const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_setsigpending"); + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_setxregs.c b/libpthread/linuxthreads.old_db/td_thr_setxregs.c new file mode 100644 index 000000000..da77ab3b4 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_setxregs.c @@ -0,0 +1,30 @@ +/* Set a thread's extra state register set. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_setxregs (const td_thrhandle_t *ta, const void *addr) +{ + /* XXX This might have to be platform specific. */ + LOG ("td_thr_setxregs"); + return TD_NOXREGS; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_sigsetmask.c b/libpthread/linuxthreads.old_db/td_thr_sigsetmask.c new file mode 100644 index 000000000..8b0eb8185 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_sigsetmask.c @@ -0,0 +1,30 @@ +/* Set a thread's signal mask. + Copyright (C) 1999, 2001 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" + + +td_err_e +td_thr_sigsetmask (const td_thrhandle_t *th, const sigset_t *ss) +{ + /* XXX We have to figure out what has to be done. */ + LOG ("td_thr_sigsetmask"); + return TD_OK; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_tls_get_addr.c b/libpthread/linuxthreads.old_db/td_thr_tls_get_addr.c new file mode 100644 index 000000000..e140b77dc --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_tls_get_addr.c @@ -0,0 +1,70 @@ +/* Get address of thread local variable. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + + +#include "link.h" +#include "thread_dbP.h" + +/* Value used for dtv entries for which the allocation is delayed. */ +# define TLS_DTV_UNALLOCATED ((void *) -1l) + + +td_err_e +td_thr_tls_get_addr (const td_thrhandle_t *th __attribute__ ((unused)), + void *map_address __attribute__ ((unused)), + size_t offset __attribute__ ((unused)), + void **address __attribute__ ((unused))) +{ +#if USE_TLS + size_t modid; + union dtv pdtv, *dtvp; + + LOG ("td_thr_tls_get_addr"); + + /* Get the DTV pointer from the thread descriptor. */ + if (ps_pdread (th->th_ta_p->ph, + &((struct _pthread_descr_struct *) th->th_unique)->p_header.data.dtvp, + &dtvp, sizeof dtvp) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Read the module ID from the link_map. */ + if (ps_pdread (th->th_ta_p->ph, + &((struct link_map *) map_address)->l_tls_modid, + &modid, sizeof modid) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Get the corresponding entry in the DTV. */ + if (ps_pdread (th->th_ta_p->ph, dtvp + modid, + &pdtv, sizeof (union dtv)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* It could be that the memory for this module is not allocated for + the given thread. */ + if (pdtv.pointer == TLS_DTV_UNALLOCATED) + /* There is not much we can do. */ + return TD_NOTALLOC; + + *address = (char *) pdtv.pointer + offset; + + return TD_OK; +#else + return TD_ERR; +#endif +} diff --git a/libpthread/linuxthreads.old_db/td_thr_tsd.c b/libpthread/linuxthreads.old_db/td_thr_tsd.c new file mode 100644 index 000000000..003ed95fe --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_tsd.c @@ -0,0 +1,82 @@ +/* Get a thread-specific data pointer for a thread. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include "../linuxthreads.old/internals.h" + + +td_err_e +td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data) +{ + struct _pthread_descr_struct pds; + struct pthread_key_struct *keys = th->th_ta_p->keys; + struct pthread_key_struct key; + int pthread_keys_max = th->th_ta_p->pthread_keys_max; + int pthread_key_2ndlevel_size = th->th_ta_p->pthread_key_2ndlevel_size; + unsigned int idx1st; + unsigned int idx2nd; + void *p; + + LOG ("td_thr_tsd"); + + /* If there is no thread descriptor there cannot be any thread + specific data. */ + if (th->th_unique == NULL) + return TD_BADKEY; + + /* Get the thread descriptor. */ + if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, + sizeof (struct _pthread_descr_struct)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Check correct value of key. */ + if (tk >= pthread_keys_max) + return TD_BADKEY; + + /* Get the key entry. */ + if (ps_pdread (th->th_ta_p->ph, &keys[tk], &key, + sizeof (struct pthread_key_struct)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* Fail if this key is not at all used. */ + if (! key.in_use) + return TD_BADKEY; + + /* Compute the indeces. */ + idx1st = tk / pthread_key_2ndlevel_size; + idx2nd = tk % pthread_key_2ndlevel_size; + + /* Check the pointer to the second level array. */ + if (pds.p_specific[idx1st] == NULL) + return TD_NOTSD; + + /* Now get the real key. + XXX I don't know whether it's correct but there is currently no + easy way to determine whether a key was never set or the value + is NULL. We return an error whenever the value is NULL. */ + if (ps_pdread (th->th_ta_p->ph, &pds.p_specific[idx1st][idx2nd], &p, + sizeof (void *)) != PS_OK) + return TD_ERR; + + if (p != NULL) + *data = p; + + return p != NULL ? TD_OK : TD_NOTSD; +} diff --git a/libpthread/linuxthreads.old_db/td_thr_validate.c b/libpthread/linuxthreads.old_db/td_thr_validate.c new file mode 100644 index 000000000..31169ef60 --- /dev/null +++ b/libpthread/linuxthreads.old_db/td_thr_validate.c @@ -0,0 +1,70 @@ +/* Validate a thread handle. + Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include "thread_dbP.h" +#include "../linuxthreads.old/internals.h" + + +td_err_e +td_thr_validate (const td_thrhandle_t *th) +{ + struct pthread_handle_struct *handles = th->th_ta_p->handles; + int pthread_threads_max = th->th_ta_p->pthread_threads_max; + int cnt; + struct pthread_handle_struct phc; + + LOG ("td_thr_validate"); + + /* A special case: if the program just starts up the handle is + NULL. */ + if (th->th_unique == NULL) + { + /* Read the first handle. If the pointer to the thread + descriptor is not NULL this is an error. */ + if (ps_pdread (th->th_ta_p->ph, handles, &phc, + sizeof (struct pthread_handle_struct)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + return phc.h_descr == NULL ? TD_OK : TD_NOTHR; + } + + /* Now get all descriptors, one after the other. */ + for (cnt = 0; cnt < pthread_threads_max; ++cnt, ++handles) + { + if (ps_pdread (th->th_ta_p->ph, handles, &phc, + sizeof (struct pthread_handle_struct)) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + if (phc.h_descr != NULL && phc.h_descr == th->th_unique) + { + struct _pthread_descr_struct pds; + + if (ps_pdread (th->th_ta_p->ph, phc.h_descr, &pds, + th->th_ta_p->sizeof_descr) != PS_OK) + return TD_ERR; /* XXX Other error value? */ + + /* XXX There should be another test using the TID but this is + currently not available. */ + return pds.p_terminated != 0 ? TD_NOTHR : TD_OK; + } + } + + return TD_ERR; +} diff --git a/libpthread/linuxthreads.old_db/thread_db.h b/libpthread/linuxthreads.old_db/thread_db.h new file mode 100644 index 000000000..f0d9aa7c3 --- /dev/null +++ b/libpthread/linuxthreads.old_db/thread_db.h @@ -0,0 +1,451 @@ +/* Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _THREAD_DB_H +#define _THREAD_DB_H 1 + +/* This is the debugger interface for the LinuxThreads library. It is + modelled closely after the interface with same names in Solaris with + the goal to share the same code in the debugger. */ +#include +#include +#include +#include + + +/* Error codes of the library. */ +typedef enum +{ + TD_OK, /* No error. */ + TD_ERR, /* No further specified error. */ + TD_NOTHR, /* No matching thread found. */ + TD_NOSV, /* No matching synchronization handle found. */ + TD_NOLWP, /* No matching light-weighted process found. */ + TD_BADPH, /* Invalid process handle. */ + TD_BADTH, /* Invalid thread handle. */ + TD_BADSH, /* Invalid synchronization handle. */ + TD_BADTA, /* Invalid thread agent. */ + TD_BADKEY, /* Invalid key. */ + TD_NOMSG, /* No event available. */ + TD_NOFPREGS, /* No floating-point register content available. */ + TD_NOLIBTHREAD, /* Application not linked with thread library. */ + TD_NOEVENT, /* Requested event is not supported. */ + TD_NOCAPAB, /* Capability not available. */ + TD_DBERR, /* Internal debug library error. */ + TD_NOAPLIC, /* Operation is not applicable. */ + TD_NOTSD, /* No thread-specific data available. */ + TD_MALLOC, /* Out of memory. */ + TD_PARTIALREG, /* Not entire register set was read or written. */ + TD_NOXREGS, /* X register set not available for given thread. */ + TD_NOTALLOC, /* TLS memory not yet allocated. */ + TD_VERSION /* Version if libpthread and libthread_db do not match. */ +} td_err_e; + + +/* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to + select threads regardless of state in td_ta_thr_iter(). */ +typedef enum +{ + TD_THR_ANY_STATE, + TD_THR_UNKNOWN, + TD_THR_STOPPED, + TD_THR_RUN, + TD_THR_ACTIVE, + TD_THR_ZOMBIE, + TD_THR_SLEEP, + TD_THR_STOPPED_ASLEEP +} td_thr_state_e; + +/* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used + to select threads regardless of type in td_ta_thr_iter(). */ +typedef enum +{ + TD_THR_ANY_TYPE, + TD_THR_USER, + TD_THR_SYSTEM +} td_thr_type_e; + + +/* Types of the debugging library. */ + +/* Handle for a process. This type is opaque. */ +typedef struct td_thragent td_thragent_t; + +/* The actual thread handle type. This is also opaque. */ +typedef struct td_thrhandle +{ + td_thragent_t *th_ta_p; + psaddr_t th_unique; +} td_thrhandle_t; + + +/* Forward declaration of a type defined by and for the dynamic linker. */ +struct link_map; + + +/* Flags for `td_ta_thr_iter'. */ +#define TD_THR_ANY_USER_FLAGS 0xffffffff +#define TD_THR_LOWEST_PRIORITY -20 +#define TD_SIGNO_MASK NULL + + +#define TD_EVENTSIZE 2 +#define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */ +#define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */ +#define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */ + +/* Bitmask of enabled events. */ +typedef struct td_thr_events +{ + uint32_t event_bits[TD_EVENTSIZE]; +} td_thr_events_t; + +/* Event set manipulation macros. */ +#define __td_eventmask(n) \ + (UINT32_C (1) << (((n) - 1) & BT_UIMASK)) +#define __td_eventword(n) \ + ((UINT32_C ((n) - 1)) >> BT_UISHIFT) + +#define td_event_emptyset(setp) \ + do { \ + int __i; \ + for (__i = TD_EVENTSIZE; __i > 0; --__i) \ + (setp)->event_bits[__i - 1] = 0; \ + } while (0) + +#define td_event_fillset(setp) \ + do { \ + int __i; \ + for (__i = TD_EVENTSIZE; __i > 0; --__i) \ + (setp)->event_bits[__i - 1] = UINT32_C (0xffffffff); \ + } while (0) + +#define td_event_addset(setp, n) \ + (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n)) +#define td_event_delset(setp, n) \ + (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n)) +#define td_eventismember(setp, n) \ + (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)])) +#if TD_EVENTSIZE == 2 +# define td_eventisempty(setp) \ + (!((setp)->event_bits[0]) && !((setp)->event_bits[1])) +#else +# error "td_eventisempty must be changed to match TD_EVENTSIZE" +#endif + +/* Events reportable by the thread implementation. */ +typedef enum +{ + TD_ALL_EVENTS, /* Pseudo-event number. */ + TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */ + TD_READY, /* Is executable now. */ + TD_SLEEP, /* Blocked in a synchronization obj. */ + TD_SWITCHTO, /* Now assigned to a process. */ + TD_SWITCHFROM, /* Not anymore assigned to a process. */ + TD_LOCK_TRY, /* Trying to get an unavailable lock. */ + TD_CATCHSIG, /* Signal posted to the thread. */ + TD_IDLE, /* Process getting idle. */ + TD_CREATE, /* New thread created. */ + TD_DEATH, /* Thread terminated. */ + TD_PREEMPT, /* Preempted. */ + TD_PRI_INHERIT, /* Inherited elevated priority. */ + TD_REAP, /* Reaped. */ + TD_CONCURRENCY, /* Number of processes changing. */ + TD_TIMEOUT, /* Conditional variable wait timed out. */ + TD_MIN_EVENT_NUM = TD_READY, + TD_MAX_EVENT_NUM = TD_TIMEOUT, + TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */ +} td_event_e; + +/* Values representing the different ways events are reported. */ +typedef enum +{ + NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */ + NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically + inserted. */ + NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */ +} td_notify_e; + +/* Description how event type is reported. */ +typedef struct td_notify +{ + td_notify_e type; /* Way the event is reported. */ + union + { + psaddr_t bptaddr; /* Address of breakpoint. */ + int syscallno; /* Number of system call used. */ + } u; +} td_notify_t; + +/* Structure used to report event. */ +typedef struct td_event_msg +{ + td_event_e event; /* Event type being reported. */ + const td_thrhandle_t *th_p; /* Thread reporting the event. */ + union + { +# if 0 + td_synchandle_t *sh; /* Handle of synchronization object. */ +#endif + uintptr_t data; /* Event specific data. */ + } msg; +} td_event_msg_t; + +/* Structure containing event data available in each thread structure. */ +typedef struct +{ + td_thr_events_t eventmask; /* Mask of enabled events. */ + td_event_e eventnum; /* Number of last event. */ + void *eventdata; /* Data associated with event. */ +} td_eventbuf_t; + + +/* Gathered statistics about the process. */ +typedef struct td_ta_stats +{ + int nthreads; /* Total number of threads in use. */ + int r_concurrency; /* Concurrency level requested by user. */ + int nrunnable_num; /* Average runnable threads, numerator. */ + int nrunnable_den; /* Average runnable threads, denominator. */ + int a_concurrency_num; /* Achieved concurrency level, numerator. */ + int a_concurrency_den; /* Achieved concurrency level, denominator. */ + int nlwps_num; /* Average number of processes in use, + numerator. */ + int nlwps_den; /* Average number of processes in use, + denominator. */ + int nidle_num; /* Average number of idling processes, + numerator. */ + int nidle_den; /* Average number of idling processes, + denominator. */ +} td_ta_stats_t; + + +/* Since Sun's library is based on Solaris threads we have to define a few + types to map them to POSIX threads. */ +typedef pthread_t thread_t; +typedef pthread_key_t thread_key_t; + + +/* Callback for iteration over threads. */ +typedef int td_thr_iter_f (const td_thrhandle_t *, void *); + +/* Callback for iteration over thread local data. */ +typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *); + + + +/* Forward declaration. This has to be defined by the user. */ +struct ps_prochandle; + + +/* Information about the thread. */ +typedef struct td_thrinfo +{ + td_thragent_t *ti_ta_p; /* Process handle. */ + unsigned int ti_user_flags; /* Unused. */ + thread_t ti_tid; /* Thread ID returned by + pthread_create(). */ + char *ti_tls; /* Pointer to thread-local data. */ + psaddr_t ti_startfunc; /* Start function passed to + pthread_create(). */ + psaddr_t ti_stkbase; /* Base of thread's stack. */ + long int ti_stksize; /* Size of thread's stack. */ + psaddr_t ti_ro_area; /* Unused. */ + int ti_ro_size; /* Unused. */ + td_thr_state_e ti_state; /* Thread state. */ + unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */ + td_thr_type_e ti_type; /* Type of the thread (system vs + user thread). */ + intptr_t ti_pc; /* Unused. */ + intptr_t ti_sp; /* Unused. */ + short int ti_flags; /* Unused. */ + int ti_pri; /* Thread priority. */ + lwpid_t ti_lid; /* Unused. */ + sigset_t ti_sigmask; /* Signal mask. */ + unsigned char ti_traceme; /* Nonzero if event reporting + enabled. */ + unsigned char ti_preemptflag; /* Unused. */ + unsigned char ti_pirecflag; /* Unused. */ + sigset_t ti_pending; /* Set of pending signals. */ + td_thr_events_t ti_events; /* Set of enabled events. */ +} td_thrinfo_t; + + + +/* Prototypes for exported library functions. */ + +/* Initialize the thread debug support library. */ +extern td_err_e td_init (void); + +/* Historical relict. Should not be used anymore. */ +extern td_err_e td_log (void); + +/* Return list of symbols the library can request. */ +extern const char **td_symbol_list (void); + +/* Generate new thread debug library handle for process PS. */ +extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta); + +/* Free resources allocated for TA. */ +extern td_err_e td_ta_delete (td_thragent_t *__ta); + +/* Get number of currently running threads in process associated with TA. */ +extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np); + +/* Return process handle passed in `td_ta_new' for process associated with + TA. */ +extern td_err_e td_ta_get_ph (const td_thragent_t *__ta, + struct ps_prochandle **__ph); + +/* Map thread library handle PT to thread debug library handle for process + associated with TA and store result in *TH. */ +extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt, + td_thrhandle_t *__th); + +/* Map process ID LWPID to thread debug library handle for process + associated with TA and store result in *TH. */ +extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid, + td_thrhandle_t *__th); + + +/* Call for each thread in a process associated with TA the callback function + CALLBACK. */ +extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta, + td_thr_iter_f *__callback, void *__cbdata_p, + td_thr_state_e __state, int __ti_pri, + sigset_t *__ti_sigmask_p, + unsigned int __ti_user_flags); + +/* Call for each defined thread local data entry the callback function KI. */ +extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki, + void *__p); + + +/* Get event address for EVENT. */ +extern td_err_e td_ta_event_addr (const td_thragent_t *__ta, + td_event_e __event, td_notify_t *__ptr); + +/* Enable EVENT in global mask. */ +extern td_err_e td_ta_set_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Disable EVENT in global mask. */ +extern td_err_e td_ta_clear_event (const td_thragent_t *__ta, + td_thr_events_t *__event); + +/* Return information about last event. */ +extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta, + td_event_msg_t *__msg); + + +/* Set suggested concurrency level for process associated with TA. */ +extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level); + + +/* Enable collecting statistics for process associated with TA. */ +extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable); + +/* Reset statistics. */ +extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta); + +/* Retrieve statistics from process associated with TA. */ +extern td_err_e td_ta_get_stats (const td_thragent_t *__ta, + td_ta_stats_t *__statsp); + + +/* Validate that TH is a thread handle. */ +extern td_err_e td_thr_validate (const td_thrhandle_t *__th); + +/* Return information about thread TH. */ +extern td_err_e td_thr_get_info (const td_thrhandle_t *__th, + td_thrinfo_t *__infop); + +/* Retrieve floating-point register contents of process running thread TH. */ +extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th, + prfpregset_t *__regset); + +/* Retrieve general register contents of process running thread TH. */ +extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th, + prgregset_t __gregs); + +/* Retrieve extended register contents of process running thread TH. */ +extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs); + +/* Get size of extended register set of process running thread TH. */ +extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep); + +/* Set floating-point register contents of process running thread TH. */ +extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th, + const prfpregset_t *__fpregs); + +/* Set general register contents of process running thread TH. */ +extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th, + prgregset_t __gregs); + +/* Set extended register contents of process running thread TH. */ +extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th, + const void *__addr); + + +/* Get address of thread local variable. */ +extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th, + void *__map_address, size_t __offset, + void **__address); + + +/* Enable reporting for EVENT for thread TH. */ +extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event); + +/* Enable EVENT for thread TH. */ +extern td_err_e td_thr_set_event (const td_thrhandle_t *__th, + td_thr_events_t *__event); + +/* Disable EVENT for thread TH. */ +extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th, + td_thr_events_t *__event); + +/* Get event message for thread TH. */ +extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th, + td_event_msg_t *__msg); + + +/* Set priority of thread TH. */ +extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio); + + +/* Set pending signals for thread TH. */ +extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th, + unsigned char __n, const sigset_t *__ss); + +/* Set signal mask for thread TH. */ +extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th, + const sigset_t *__ss); + + +/* Return thread local data associated with key TK in thread TH. */ +extern td_err_e td_thr_tsd (const td_thrhandle_t *__th, + const thread_key_t __tk, void **__data); + + +/* Suspend execution of thread TH. */ +extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th); + +/* Resume execution of thread TH. */ +extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th); + +#endif /* thread_db.h */ diff --git a/libpthread/linuxthreads.old_db/thread_dbP.h b/libpthread/linuxthreads.old_db/thread_dbP.h new file mode 100644 index 000000000..a979a44a9 --- /dev/null +++ b/libpthread/linuxthreads.old_db/thread_dbP.h @@ -0,0 +1,110 @@ +/* Private header for thread debug library. */ +#ifndef _THREAD_DBP_H +#define _THREAD_DBP_H 1 + +#define __FORCE_GLIBC +#include +#include +#include +#include "proc_service.h" +#include "thread_db.h" +#include "../linuxthreads.old/internals.h" + + +/* Indeces for the symbol names. */ +enum + { + PTHREAD_THREADS_EVENTS = 0, + PTHREAD_LAST_EVENT, + PTHREAD_HANDLES_NUM, + PTHREAD_HANDLES, + PTHREAD_KEYS, + LINUXTHREADS_PTHREAD_THREADS_MAX, + LINUXTHREADS_PTHREAD_KEYS_MAX, + LINUXTHREADS_PTHREAD_SIZEOF_DESCR, + LINUXTHREADS_CREATE_EVENT, + LINUXTHREADS_DEATH_EVENT, + LINUXTHREADS_REAP_EVENT, + LINUXTHREADS_INITIAL_REPORT_EVENTS, + LINUXTHREADS_VERSION, + NUM_MESSAGES + }; + + +/* Comment out the following for less verbose output. */ +#ifndef NDEBUG +# define LOG(c) if (__td_debug) __libc_write (2, c "\n", strlen (c "\n")) +extern int __td_debug; +#else +# define LOG(c) +#endif + + +/* Handle for a process. This type is opaque. */ +struct td_thragent +{ + /* Delivered by the debugger and we have to pass it back in the + proc callbacks. */ + struct ps_prochandle *ph; + + /* Some cached information. */ + + /* Address of the `__pthread_handles' array. */ + struct pthread_handle_struct *handles; + + /* Address of the `pthread_kyes' array. */ + struct pthread_key_struct *keys; + + /* Maximum number of threads. */ + int pthread_threads_max; + + /* Maximum number of thread-local data keys. */ + int pthread_keys_max; + + /* Size of 2nd level array for thread-local data keys. */ + int pthread_key_2ndlevel_size; + + /* Sizeof struct _pthread_descr_struct. */ + int sizeof_descr; + + /* Pointer to the `__pthread_threads_events' variable in the target. */ + psaddr_t pthread_threads_eventsp; + + /* Pointer to the `__pthread_last_event' variable in the target. */ + psaddr_t pthread_last_event; + + /* Pointer to the `__pthread_handles_num' variable. */ + psaddr_t pthread_handles_num; +}; + + +/* Type used internally to keep track of thread agent descriptors. */ +struct agent_list +{ + td_thragent_t *ta; + struct agent_list *next; +}; + +/* List of all known descriptors. */ +extern struct agent_list *__td_agent_list; + +/* Function used to test for correct thread agent pointer. */ +static inline int +ta_ok (const td_thragent_t *ta) +{ + struct agent_list *runp = __td_agent_list; + + if (ta == NULL) + return 0; + + while (runp != NULL && runp->ta != ta) + runp = runp->next; + + return runp != NULL; +} + + +/* Internal wrapper around ps_pglobal_lookup. */ +extern int td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr); + +#endif /* thread_dbP.h */ diff --git a/libpthread/linuxthreads/Changes b/libpthread/linuxthreads/Changes deleted file mode 100644 index b213f36c5..000000000 --- a/libpthread/linuxthreads/Changes +++ /dev/null @@ -1,85 +0,0 @@ -Release 0.9: -- more ports (SH, IA-64, s390) -- many bug fixes -- timed sync object wait functions -- barrier implementation -- spinlocks implementation -- thread register on x86 -- variable stack size and position on some platforms - -Release 0.8: -(ehmm, forgot to update, don't know anymore) - -Release 0.7: -- Destructors for thread-specific data now conform to the POSIX semantics - (call destructors again if non-NULL TSD remains after a round of - destruction). -- Implemented thread-specific data as a sparse array, allows more TSD keys - and smaller thread descriptors (Ulrich Drepper). -- Added "error checking" mutexes. -- Protect against multiple sigwait() on the same signals. -- Simplified implementation of semaphores when compare_and_swap is - not available. -- Fixed bug in fork() where stdin was closed if fork() was called before - the first pthread_create(). -- Fixed bug in the gethostby*_r functions (bad result if null bytes - in addresses). -- Typos in manual pages corrected. -- First cut at a PowerPC port (not working yet, runs into problems - with gcc and with the C library). - -Release 0.6: -- Validation of thread identifiers: no more crashes when operating on - a thread that has exited (based on Pavel Krauz's ideas). -- Added fallback implementation of semaphores for the 386 and the - Sparc. -- Fixed a bug in signal handling causing false restarts of suspended - threads. -- Fixed a bug in realtime scheduling causing all threads to have - default scheduling on Ix86 with libc5. -- With realtime scheduling, unlocking a mutex now restarts the - highest priority thread waiting on the mutex, not the - first-suspended thread (Richard Neitzel). -- Timing a process now returns cumulative times for all threads, not - just times for the initial thread (suggested by Wolfram Gloger). -- Cleaned up name space (internal defs prefixed by __, weak aliases - for non-portable extensions). -- MIPS port (contributed by Ralf Baechle). - -Release 0.5: -- Signal-safe semaphores a la POSIX 1003.1b added. -- Locking bug in pthread_mutex_trylock over recursive mutexes fixed. -- Race conditions in thread cancellation fixed. -- Sparc port (contributed by Miguel de Icaza). -- Support for getpwnam_r and getpwuid_r. -- Added pthread_kill_other_threads_np to be used in conjunction with - exec*(). - -Release 0.4: -- Manual pages for all functions. -- Synchronization bug causing accumulation of zombie processes fixed. -- Race condition in pthread_cond_timedwait fixed. -- Recursive mutexes are back by popular demand. -- Partial support for realtime scheduling (initiated by Richard Neitzel). -- pthread.h cleaned up a lot: now C++ compatible, added missing "const" - qualifiers, added short documentation, put to GNU libc standards - for name space pollution (Ulrich Drepper). -- Motorola 68k port (contributed by Andreas Schwab). -- Interaction with fork(2) cleaned up a lot. - -Release 0.3: -- Thread creation and reclaimation now performed by a centralized - "thread manager" thread. -- Removed recursive mutexes to make regular mutexes more efficient. -- Now available as a shared library (contributed by Richard Henderson). -- Alpha port (contributed by Richard Henderson). -- Fixed many small discrepancies with Posix 1003.1c. -- Put under the LGPL instead of the GPL. - -Release 0.2: -- Reentrant libc functions (adapted from libc 5.3.9 by Peeter Joot) -- pthread_cond_wait did not reacquire the mutex correctly on return -- More efficient pthread_cond_broadcast - -Release 0.1: -- First public release diff --git a/libpthread/linuxthreads/FAQ.html b/libpthread/linuxthreads/FAQ.html deleted file mode 100644 index 21be33ec4..000000000 --- a/libpthread/linuxthreads/FAQ.html +++ /dev/null @@ -1,1039 +0,0 @@ - - -LinuxThreads Frequently Asked Questions - - -

LinuxThreads Frequently Asked Questions
- (with answers)

-

[For LinuxThreads version 0.8]

- -

- -A. The big picture
-B. Getting more information
-C. Issues related to the C library
-D. Problems, weird behaviors, potential bugs
-E. Missing functions, wrong types, etc
-F. C++ issues
-G. Debugging LinuxThreads programs
-H. Compiling multithreaded code; errno madness
-I. X-Windows and other libraries
-J. Signals and threads
-K. Internals of LinuxThreads

- -


-

- -

A. The big picture

- -

A.1: What is LinuxThreads?

- -LinuxThreads is a Linux library for multi-threaded programming. -It implements the Posix 1003.1c API (Application Programming -Interface) for threads. It runs on any Linux system with kernel 2.0.0 -or more recent, and a suitable C library (see section C). -

- -

A.2: What are threads?

- -A thread is a sequential flow of control through a program. -Multi-threaded programming is, thus, a form of parallel programming -where several threads of control are executing concurrently in the -program. All threads execute in the same memory space, and can -therefore work concurrently on shared data.

- -Multi-threaded programming differs from Unix-style multi-processing in -that all threads share the same memory space (and a few other system -resources, such as file descriptors), instead of running in their own -memory space as is the case with Unix processes.

- -Threads are useful for two reasons. First, they allow a program to -exploit multi-processor machines: the threads can run in parallel on -several processors, allowing a single program to divide its work -between several processors, thus running faster than a single-threaded -program, which runs on only one processor at a time. Second, some -programs are best expressed as several threads of control that -communicate together, rather than as one big monolithic sequential -program. Examples include server programs, overlapping asynchronous -I/O, and graphical user interfaces.

- -

A.3: What is POSIX 1003.1c?

- -It's an API for multi-threaded programming standardized by IEEE as -part of the POSIX standards. Most Unix vendors have endorsed the -POSIX 1003.1c standard. Implementations of the 1003.1c API are -already available under Sun Solaris 2.5, Digital Unix 4.0, -Silicon Graphics IRIX 6, and should soon be available from other -vendors such as IBM and HP. More generally, the 1003.1c API is -replacing relatively quickly the proprietary threads library that were -developed previously under Unix, such as Mach cthreads, Solaris -threads, and IRIX sprocs. Thus, multithreaded programs using the -1003.1c API are likely to run unchanged on a wide variety of Unix -platforms.

- -

A.4: What is the status of LinuxThreads?

- -LinuxThreads implements almost all of Posix 1003.1c, as well as a few -extensions. The only part of LinuxThreads that does not conform yet -to Posix is signal handling (see section J). Apart -from the signal stuff, all the Posix 1003.1c base functionality, -as well as a number of optional extensions, are provided and conform -to the standard (to the best of my knowledge). -The signal stuff is hard to get right, at least without special kernel -support, and while I'm definitely looking at ways to implement the -Posix behavior for signals, this might take a long time before it's -completed.

- -

A.5: How stable is LinuxThreads?

- -The basic functionality (thread creation and termination, mutexes, -conditions, semaphores) is very stable. Several industrial-strength -programs, such as the AOL multithreaded Web server, use LinuxThreads -and seem quite happy about it. There used to be some rough edges in -the LinuxThreads / C library interface with libc 5, but glibc 2 -fixes all of those problems and is now the standard C library on major -Linux distributions (see section C).

- -


-

- -

B. Getting more information

- -

B.1: What are good books and other sources of -information on POSIX threads?

- -The FAQ for comp.programming.threads lists several books: -http://www.serpentine.com/~bos/threads-faq/.

- -There are also some online tutorials. Follow the links from the -LinuxThreads web page: -http://pauillac.inria.fr/~xleroy/linuxthreads.

- -

B.2: I'd like to be informed of future developments on -LinuxThreads. Is there a mailing list for this purpose?

- -I post LinuxThreads-related announcements on the newsgroup -comp.os.linux.announce, -and also on the mailing list -linux-threads@magenet.com. -You can subscribe to the latter by writing -majordomo@magenet.com.

- -

B.3: What are good places for discussing -LinuxThreads?

- -For questions about programming with POSIX threads in general, use -the newsgroup -comp.programming.threads. -Be sure you read the -FAQ -for this group before you post.

- -For Linux-specific questions, use -comp.os.linux.development.apps -and comp.os.linux.development.kernel. -The latter is especially appropriate for questions relative to the -interface between the kernel and LinuxThreads.

- -

B.4: How should I report a possible bug in -LinuxThreads?

- -If you're using glibc 2, the best way by far is to use the -glibcbug script to mail a bug report to the glibc -maintainers.

- -If you're using an older libc, or don't have the glibcbug -script on your machine, then e-mail me directly -(Xavier.Leroy@inria.fr).

- -In both cases, before sending the bug report, make sure that it is not -addressed already in this FAQ. Also, try to send a short program that -reproduces the weird behavior you observed.

- -

B.5: I'd like to read the POSIX 1003.1c standard. Is -it available online?

- -Unfortunately, no. POSIX standards are copyrighted by IEEE, and -IEEE does not distribute them freely. You can buy paper copies from -IEEE, but the price is fairly high ($120 or so). If you disagree with -this policy and you're an IEEE member, be sure to let them know.

- -On the other hand, you probably don't want to read the standard. It's -very hard to read, written in standard-ese, and targeted to -implementors who already know threads inside-out. A good book on -POSIX threads provides the same information in a much more readable form. -I can personally recommend Dave Butenhof's book, Programming -with POSIX threads (Addison-Wesley). Butenhof was part of the -POSIX committee and also designed the Digital Unix implementations of -POSIX threads, and it shows.

- -Another good source of information is the X/Open Group Single Unix -specification which is available both -on-line -and as a -book and CD/ROM. -That specification includes pretty much all the POSIX standards, -including 1003.1c, with some extensions and clarifications.

- -


-

- -

C. Issues related to the C library

- -

C.1: Which version of the C library should I use -with LinuxThreads?

- -The best choice by far is glibc 2, a.k.a. libc 6. It offers very good -support for multi-threading, and LinuxThreads has been closely -integrated with glibc 2. The glibc 2 distribution contains the -sources of a specially adapted version of LinuxThreads.

- -glibc 2 comes preinstalled as the default C library on several Linux -distributions, such as RedHat 5 and up, and Debian 2. -Those distributions include the version of LinuxThreads matching -glibc 2.

- -

C.2: My system has libc 5 preinstalled, not glibc -2. Can I still use LinuxThreads?

- -Yes, but you're likely to run into some problems, as libc 5 only -offers minimal support for threads and contains some bugs that affect -multithreaded programs.

- -The versions of libc 5 that work best with LinuxThreads are -libc 5.2.18 on the one hand, and libc 5.4.12 or later on the other hand. -Avoid 5.3.12 and 5.4.7: these have problems with the per-thread errno -variable.

- -

C.3: So, should I switch to glibc 2, or stay with a -recent libc 5?

- -I'd recommend you switch to glibc 2. Even for single-threaded -programs, glibc 2 is more solid and more standard-conformant than libc -5. And the shortcomings of libc 5 almost preclude any serious -multi-threaded programming.

- -Switching an already installed -system from libc 5 to glibc 2 is not completely straightforward. -See the Glibc2 -HOWTO for more information. Much easier is (re-)installing a -Linux distribution based on glibc 2, such as RedHat 6.

- -

C.4: Where can I find glibc 2 and the version of -LinuxThreads that goes with it?

- -On prep.ai.mit.edu and its many, many mirrors around the world. -See http://www.gnu.org/order/ftp.html -for a list of mirrors.

- -

C.5: Where can I find libc 5 and the version of -LinuxThreads that goes with it?

- -For libc 5, see ftp://sunsite.unc.edu/pub/Linux/devel/GCC/.

- -For the libc 5 version of LinuxThreads, see -ftp://ftp.inria.fr/INRIA/Projects/cristal/Xavier.Leroy/linuxthreads/.

- -

C.6: How can I recompile the glibc 2 version of the -LinuxThreads sources?

- -You must transfer the whole glibc sources, then drop the LinuxThreads -sources in the linuxthreads/ subdirectory, then recompile -glibc as a whole. There are now too many inter-dependencies between -LinuxThreads and glibc 2 to allow separate re-compilation of LinuxThreads. -

- -

C.7: What is the correspondence between LinuxThreads -version numbers, libc version numbers, and RedHat version -numbers?

- -Here is a summary. (Information on Linux distributions other than -RedHat are welcome.)

- - - - - - - -
LinuxThreads C library RedHat
0.7, 0.71 (for libc 5) libc 5.x RH 4.2
0.7, 0.71 (for glibc 2) glibc 2.0.x RH 5.x
0.8 glibc 2.1.1 RH 6.0
0.8 glibc 2.1.2 not yet released
-

- -


-

- -

D. Problems, weird behaviors, potential bugs

- -

D.1: When I compile LinuxThreads, I run into problems in -file libc_r/dirent.c

- -You probably mean: -
-        libc_r/dirent.c:94: structure has no member named `dd_lock'
-
-I haven't actually seen this problem, but several users reported it. -My understanding is that something is wrong in the include files of -your Linux installation (/usr/include/*). Make sure -you're using a supported version of the libc 5 library. (See question C.2).

- -

D.2: When I compile LinuxThreads, I run into problems with -/usr/include/sched.h: there are several occurrences of -_p that the C compiler does not understand

- -Yes, /usr/include/sched.h that comes with libc 5.3.12 is broken. -Replace it with the sched.h file contained in the -LinuxThreads distribution. But really you should not be using libc -5.3.12 with LinuxThreads! (See question C.1.)

- -

D.3: My program does fdopen() on a file -descriptor opened on a pipe. When I link it with LinuxThreads, -fdopen() always returns NULL!

- -You're using one of the buggy versions of libc (5.3.12, 5.4.7., etc). -See question C.1 above.

- -

D.4: My program creates a lot of threads, and after -a while pthread_create() no longer returns!

- -This is known bug in the version of LinuxThreads that comes with glibc -2.1.1. An upgrade to 2.1.2 is recommended.

- -

D.5: When I'm running a program that creates N -threads, top or ps -display N+2 processes that are running my program. What do all these -processes correspond to?

- -Due to the general "one process per thread" model, there's one process -for the initial thread and N processes for the threads it created -using pthread_create. That leaves one process -unaccounted for. That extra process corresponds to the "thread -manager" thread, a thread created internally by LinuxThreads to handle -thread creation and thread termination. This extra thread is asleep -most of the time. - -

D.6: Scheduling seems to be very unfair when there -is strong contention on a mutex: instead of giving the mutex to each -thread in turn, it seems that it's almost always the same thread that -gets the mutex. Isn't this completely broken behavior?

- -That behavior has mostly disappeared in recent releases of -LinuxThreads (version 0.8 and up). It was fairly common in older -releases, though. - -What happens in LinuxThreads 0.7 and before is the following: when a -thread unlocks a mutex, all other threads that were waiting on the -mutex are sent a signal which makes them runnable. However, the -kernel scheduler may or may not restart them immediately. If the -thread that unlocked the mutex tries to lock it again immediately -afterwards, it is likely that it will succeed, because the threads -haven't yet restarted. This results in an apparently very unfair -behavior, when the same thread repeatedly locks and unlocks the mutex, -while other threads can't lock the mutex.

- -In LinuxThreads 0.8 and up, pthread_unlock restarts only -one waiting thread, and pre-assign the mutex to that thread. Hence, -if the thread that unlocked the mutex tries to lock it again -immediately, it will block until other waiting threads have had a -chance to lock and unlock the mutex. This results in much fairer -scheduling.

- -Notice however that even the old "unfair" behavior is perfectly -acceptable with respect to the POSIX standard: for the default -scheduling policy, POSIX makes no guarantees of fairness, such as "the -thread waiting for the mutex for the longest time always acquires it -first". Properly written multithreaded code avoids that kind of heavy -contention on mutexes, and does not run into fairness problems. If -you need scheduling guarantees, you should consider using the -real-time scheduling policies SCHED_RR and -SCHED_FIFO, which have precisely defined scheduling -behaviors.

- -

D.7: I have a simple test program with two threads -that do nothing but printf() in tight loops, and from the -printout it seems that only one thread is running, the other doesn't -print anything!

- -Again, this behavior is characteristic of old releases of LinuxThreads -(0.7 and before); more recent versions (0.8 and up) should not exhibit -this behavior.

- -The reason for this behavior is explained in -question D.6 above: printf() performs -locking on stdout, and thus your two threads contend very -heavily for the mutex associated with stdout. But if you -do some real work between two calls to printf(), you'll -see that scheduling becomes much smoother.

- -

D.8: I've looked at <pthread.h> -and there seems to be a gross error in the pthread_cleanup_push -macro: it opens a block with { but does not close it! -Surely you forgot a } at the end of the macro, right? -

- -Nope. That's the way it should be. The closing brace is provided by -the pthread_cleanup_pop macro. The POSIX standard -requires pthread_cleanup_push and -pthread_cleanup_pop to be used in matching pairs, at the -same level of brace nesting. This allows -pthread_cleanup_push to open a block in order to -stack-allocate some data structure, and -pthread_cleanup_pop to close that block. It's ugly, but -it's the standard way of implementing cleanup handlers.

- -

D.9: I tried to use real-time threads and my program -loops like crazy and freezes the whole machine!

- -Versions of LinuxThreads prior to 0.8 are susceptible to ``livelocks'' -(one thread loops, consuming 100% of the CPU time) in conjunction with -real-time scheduling. Since real-time threads and processes have -higher priority than normal Linux processes, all other processes on -the machine, including the shell, the X server, etc, cannot run and -the machine appears frozen.

- -The problem is fixed in LinuxThreads 0.8.

- -

D.10: My application needs to create thousands of -threads, or maybe even more. Can I do this with -LinuxThreads?

- -No. You're going to run into several hard limits: -
    -
  • Each thread, from the kernel's standpoint, is one process. Stock -Linux kernels are limited to at most 512 processes for the super-user, -and half this number for regular users. This can be changed by -changing NR_TASKS in include/linux/tasks.h -and recompiling the kernel. On the x86 processors at least, -architectural constraints seem to limit NR_TASKS to 4090 -at most. -
  • LinuxThreads contains a table of all active threads. This table -has room for 1024 threads at most. To increase this limit, you must -change PTHREAD_THREADS_MAX in the LinuxThreads sources -and recompile. -
  • By default, each thread reserves 2M of virtual memory space for -its stack. This space is just reserved; actual memory is allocated -for the stack on demand. But still, on a 32-bit processor, the total -virtual memory space available for the stacks is on the order of 1G, -meaning that more than 500 threads will have a hard time fitting in. -You can overcome this limitation by moving to a 64-bit platform, or by -allocating smaller stacks yourself using the setstackaddr -attribute. -
  • Finally, the Linux kernel contains many algorithms that run in -time proportional to the number of process table entries. Increasing -this number drastically will slow down the kernel operations -noticeably. -
-(Other POSIX threads libraries have similar limitations, by the way.) -For all those reasons, you'd better restructure your application so -that it doesn't need more than, say, 100 threads. For instance, -in the case of a multithreaded server, instead of creating a new -thread for each connection, maintain a fixed-size pool of worker -threads that pick incoming connection requests from a queue.

- -


-

- -

E. Missing functions, wrong types, etc

- -

E.1: Where is pthread_yield() ? How -comes LinuxThreads does not implement it?

- -Because it's not part of the (final) POSIX 1003.1c standard. -Several drafts of the standard contained pthread_yield(), -but then the POSIX guys discovered it was redundant with -sched_yield() and dropped it. So, just use -sched_yield() instead. - -

E.2: I've found some type errors in -<pthread.h>. -For instance, the second argument to pthread_create() -should be a pthread_attr_t, not a -pthread_attr_t *. Also, didn't you forget to declare -pthread_attr_default?

- -No, I didn't. What you're describing is draft 4 of the POSIX -standard, which is used in OSF DCE threads. LinuxThreads conforms to the -final standard. Even though the functions have the same names as in -draft 4 and DCE, their calling conventions are slightly different. In -particular, attributes are passed by reference, not by value, and -default attributes are denoted by the NULL pointer. Since draft 4/DCE -will eventually disappear, you'd better port your program to use the -standard interface.

- -

E.3: I'm porting an application from Solaris and I -have to rename all thread functions from thr_blah to -pthread_blah. This is very annoying. Why did you change -all the function names?

- -POSIX did it. The thr_* functions correspond to Solaris -threads, an older thread interface that you'll find only under -Solaris. The pthread_* functions correspond to POSIX -threads, an international standard available for many, many platforms. -Even Solaris 2.5 and later support the POSIX threads interface. So, -do yourself a favor and rewrite your code to use POSIX threads: this -way, it will run unchanged under Linux, Solaris, and quite a lot of -other platforms.

- -

E.4: How can I suspend and resume a thread from -another thread? Solaris has the thr_suspend() and -thr_resume() functions to do that; why don't you?

- -The POSIX standard provides no mechanism by which a thread A can -suspend the execution of another thread B, without cooperation from B. -The only way to implement a suspend/restart mechanism is to have B -check periodically some global variable for a suspend request -and then suspend itself on a condition variable, which another thread -can signal later to restart B.

- -Notice that thr_suspend() is inherently dangerous and -prone to race conditions. For one thing, there is no control on where -the target thread stops: it can very well be stopped in the middle of -a critical section, while holding mutexes. Also, there is no -guarantee on when the target thread will actually stop. For these -reasons, you'd be much better off using mutexes and conditions -instead. The only situations that really require the ability to -suspend a thread are debuggers and some kind of garbage collectors.

- -If you really must suspend a thread in LinuxThreads, you can send it a -SIGSTOP signal with pthread_kill. Send -SIGCONT for restarting it. -Beware, this is specific to LinuxThreads and entirely non-portable. -Indeed, a truly conforming POSIX threads implementation will stop all -threads when one thread receives the SIGSTOP signal! -One day, LinuxThreads will implement that behavior, and the -non-portable hack with SIGSTOP won't work anymore.

- -

E.5: Does LinuxThreads implement -pthread_attr_setstacksize() and -pthread_attr_setstackaddr()?

- -These optional functions are provided in recent versions of -LinuxThreads (0.8 and up). Earlier releases did not provide these -optional components of the POSIX standard.

- -Even if pthread_attr_setstacksize() and -pthread_attr_setstackaddr() are now provided, we still -recommend that you do not use them unless you really have strong -reasons for doing so. The default stack allocation strategy for -LinuxThreads is nearly optimal: stacks start small (4k) and -automatically grow on demand to a fairly large limit (2M). -Moreover, there is no portable way to estimate the stack requirements -of a thread, so setting the stack size yourself makes your program -less reliable and non-portable.

- -

E.6: LinuxThreads does not support the -PTHREAD_SCOPE_PROCESS value of the "contentionscope" -attribute. Why?

- -With a "one-to-one" model, as in LinuxThreads (one kernel execution -context per thread), there is only one scheduler for all processes and -all threads on the system. So, there is no way to obtain the behavior of -PTHREAD_SCOPE_PROCESS. - -

E.7: LinuxThreads does not implement process-shared -mutexes, conditions, and semaphores. Why?

- -This is another optional component of the POSIX standard. Portable -applications should test _POSIX_THREAD_PROCESS_SHARED -before using this facility. -

-The goal of this extension is to allow different processes (with -different address spaces) to synchronize through mutexes, conditions -or semaphores allocated in shared memory (either SVR4 shared memory -segments or mmap()ed files). -

-The reason why this does not work in LinuxThreads is that mutexes, -conditions, and semaphores are not self-contained: their waiting -queues contain pointers to linked lists of thread descriptors, and -these pointers are meaningful only in one address space. -

-Matt Messier and I spent a significant amount of time trying to design a -suitable mechanism for sharing waiting queues between processes. We -came up with several solutions that combined two of the following -three desirable features, but none that combines all three: -

    -
  • allow sharing between processes having different UIDs -
  • supports cancellation -
  • supports pthread_cond_timedwait -
-We concluded that kernel support is required to share mutexes, -conditions and semaphores between processes. That's one place where -Linus Torvalds's intuition that "all we need in the kernel is -clone()" fails. -

-Until suitable kernel support is available, you'd better use -traditional interprocess communications to synchronize different -processes: System V semaphores and message queues, or pipes, or sockets. -

- -


-

- -

F. C++ issues

- -

F.1: Are there C++ wrappers for LinuxThreads?

- -Douglas Schmidt's ACE library contains, among a lot of other -things, C++ wrappers for LinuxThreads and quite a number of other -thread libraries. Check out -http://www.cs.wustl.edu/~schmidt/ACE.html

- -

F.2: I'm trying to use LinuxThreads from a C++ -program, and the compiler complains about the third argument to -pthread_create() !

- -You're probably trying to pass a class member function or some -other C++ thing as third argument to pthread_create(). -Recall that pthread_create() is a C function, and it must -be passed a C function as third argument.

- -

F.3: I'm trying to use LinuxThreads in conjunction -with libg++, and I'm having all sorts of trouble.

- ->From what I understand, thread support in libg++ is completely broken, -especially with respect to locking of iostreams. H.J.Lu wrote: -
-If you want to use thread, I can only suggest egcs and glibc. You -can find egcs at -http://www.cygnus.com/egcs. -egcs has libsdtc++, which is MT safe under glibc 2. If you really -want to use the libg++, I have a libg++ add-on for egcs. -
-
-

- -

G. Debugging LinuxThreads programs

- -

G.1: Can I debug LinuxThreads program using gdb?

- -Yes, but not with the stock gdb 4.17. You need a specially patched -version of gdb 4.17 developed by Eric Paire and colleages at The Open -Group, Grenoble. The patches against gdb 4.17 are available at -http://www.gr.opengroup.org/java/jdk/linux/debug.htm. -Precompiled binaries of the patched gdb are available in RedHat's RPM -format at http://odin.appliedtheory.com/.

- -Some Linux distributions provide an already-patched version of gdb; -others don't. For instance, the gdb in RedHat 5.2 is thread-aware, -but apparently not the one in RedHat 6.0. Just ask (politely) the -makers of your Linux distributions to please make sure that they apply -the correct patches to gdb.

- -

G.2: Does it work with post-mortem debugging?

- -Not very well. Generally, the core file does not correspond to the -thread that crashed. The reason is that the kernel will not dump core -for a process that shares its memory with other processes, such as the -other threads of your program. So, the thread that crashes silently -disappears without generating a core file. Then, all other threads of -your program die on the same signal that killed the crashing thread. -(This is required behavior according to the POSIX standard.) The last -one that dies is no longer sharing its memory with anyone else, so the -kernel generates a core file for that thread. Unfortunately, that's -not the thread you are interested in. - -

G.3: Any other ways to debug multithreaded programs, then?

- -Assertions and printf() are your best friends. Try to debug -sequential parts in a single-threaded program first. Then, put -printf() statements all over the place to get execution traces. -Also, check invariants often with the assert() macro. In truth, -there is no other effective way (save for a full formal proof of your -program) to track down concurrency bugs. Debuggers are not really -effective for subtle concurrency problems, because they disrupt -program execution too much.

- -


-

- -

H. Compiling multithreaded code; errno madness

- -

H.1: You say all multithreaded code must be compiled -with _REENTRANT defined. What difference does it make?

- -It affects include files in three ways: -
    -
  • The include files define prototypes for the reentrant variants of -some of the standard library functions, -e.g. gethostbyname_r() as a reentrant equivalent to -gethostbyname().

    - -

  • If _REENTRANT is defined, some -<stdio.h> functions are no longer defined as macros, -e.g. getc() and putc(). In a multithreaded -program, stdio functions require additional locking, which the macros -don't perform, so we must call functions instead.

    - -

  • More importantly, <errno.h> redefines errno when -_REENTRANT is -defined, so that errno refers to the thread-specific errno location -rather than the global errno variable. This is achieved by the -following #define in <errno.h>: -
    -        #define errno (*(__errno_location()))
    -
    -which causes each reference to errno to call the -__errno_location() function for obtaining the location -where error codes are stored. libc provides a default definition of -__errno_location() that always returns -&errno (the address of the global errno variable). Thus, -for programs not linked with LinuxThreads, defining -_REENTRANT makes no difference w.r.t. errno processing. -But LinuxThreads redefines __errno_location() to return a -location in the thread descriptor reserved for holding the current -value of errno for the calling thread. Thus, each thread operates on -a different errno location. -
-

- -

H.2: Why is it so important that each thread has its -own errno variable?

- -If all threads were to store error codes in the same, global errno -variable, then the value of errno after a system call or library -function returns would be unpredictable: between the time a system -call stores its error code in the global errno and your code inspects -errno to see which error occurred, another thread might have stored -another error code in the same errno location.

- -

H.3: What happens if I link LinuxThreads with code -not compiled with -D_REENTRANT?

- -Lots of trouble. If the code uses getc() or -putc(), it will perform I/O without proper interlocking -of the stdio buffers; this can cause lost output, duplicate output, or -just crash other stdio functions. If the code consults errno, it will -get back the wrong error code. The following code fragment is a -typical example: -
-        do {
-          r = read(fd, buf, n);
-          if (r == -1) {
-            if (errno == EINTR)   /* an error we can handle */
-              continue;
-            else {                /* other errors are fatal */
-              perror("read failed");
-              exit(100);
-            }
-          }
-        } while (...);
-
-Assume this code is not compiled with -D_REENTRANT, and -linked with LinuxThreads. At run-time, read() is -interrupted. Since the C library was compiled with --D_REENTRANT, read() stores its error code -in the location pointed to by __errno_location(), which -is the thread-local errno variable. Then, the code above sees that -read() returns -1 and looks up errno. Since -_REENTRANT is not defined, the reference to errno -accesses the global errno variable, which is most likely 0. Hence the -code concludes that it cannot handle the error and stops.

- -

H.4: With LinuxThreads, I can no longer use the signals -SIGUSR1 and SIGUSR2 in my programs! Why?

- -The short answer is: because the Linux kernel you're using does not -support realtime signals.

- -LinuxThreads needs two signals for its internal operation. -One is used to suspend and restart threads blocked on mutex, condition -or semaphore operations. The other is used for thread -cancellation.

- -On ``old'' kernels (2.0 and early 2.1 kernels), there are only 32 -signals available and the kernel reserves all of them but two: -SIGUSR1 and SIGUSR2. So, LinuxThreads has -no choice but use those two signals.

- -On recent kernels (2.2 and up), more than 32 signals are provided in -the form of realtime signals. When run on one of those kernels, -LinuxThreads uses two reserved realtime signals for its internal -operation, thus leaving SIGUSR1 and SIGUSR2 -free for user code. (This works only with glibc, not with libc 5.)

- -

H.5: Is the stack of one thread visible from the -other threads? Can I pass a pointer into my stack to other threads? -

- -Yes, you can -- if you're very careful. The stacks are indeed visible -from all threads in the system. Some non-POSIX thread libraries seem -to map the stacks for all threads at the same virtual addresses and -change the memory mapping when they switch from one thread to -another. But this is not the case for LinuxThreads, as it would make -context switching between threads more expensive, and at any rate -might not conform to the POSIX standard.

- -So, you can take the address of an "auto" variable and pass it to -other threads via shared data structures. However, you need to make -absolutely sure that the function doing this will not return as long -as other threads need to access this address. It's the usual mistake -of returning the address of an "auto" variable, only made much worse -because of concurrency. It's much, much safer to systematically -heap-allocate all shared data structures.

- -


-

- -

I. X-Windows and other libraries

- -

I.1: My program uses both Xlib and LinuxThreads. -It stops very early with an "Xlib: unknown 0 error" message. What -does this mean?

- -That's a prime example of the errno problem described in question H.2. The binaries for Xlib you're using have not been -compiled with -D_REENTRANT. It happens Xlib contains a -piece of code very much like the one in question H.2. So, your Xlib fetches the error code from the -wrong errno location and concludes that an error it cannot handle -occurred.

- -

I.2: So, what can I do to build a multithreaded X -Windows client?

- -The best solution is to use X libraries that have been compiled with -multithreading options set. Linux distributions that come with glibc -2 as the main C library generally provide thread-safe X libraries. -At least, that seems to be the case for RedHat 5 and later.

- -You can try to recompile yourself the X libraries with multithreading -options set. They contain optional support for multithreading; it's -just that the binaries provided by your Linux distribution were built -without this support. See the file README.Xfree3.3 in -the LinuxThreads distribution for patches and info on how to compile -thread-safe X libraries from the Xfree3.3 distribution. The Xfree3.3 -sources are readily available in most Linux distributions, e.g. as a -source RPM for RedHat. Be warned, however, that X Windows is a huge -system, and recompiling even just the libraries takes a lot of time -and disk space.

- -Another, less involving solution is to call X functions only from the -main thread of your program. Even if all threads have their own errno -location, the main thread uses the global errno variable for its errno -location. Thus, code not compiled with -D_REENTRANT -still "sees" the right error values if it executes in the main thread -only.

- -

This is a lot of work. Don't you have precompiled -thread-safe X libraries that you could distribute?

- -No, I don't. Sorry. But consider installing a Linux distribution -that comes with thread-safe X libraries, such as RedHat 6.

- -

I.3: Can I use library FOO in a multithreaded -program?

- -Most libraries cannot be used "as is" in a multithreaded program. -For one thing, they are not necessarily thread-safe: calling -simultaneously two functions of the library from two threads might not -work, due to internal use of global variables and the like. Second, -the libraries must have been compiled with -D_REENTRANT to avoid -the errno problems explained in question H.2. -

- -

I.4: What if I make sure that only one thread calls -functions in these libraries?

- -This avoids problems with the library not being thread-safe. But -you're still vulnerable to errno problems. At the very least, a -recompile of the library with -D_REENTRANT is needed. -

- -

I.5: What if I make sure that only the main thread -calls functions in these libraries?

- -That might actually work. As explained in question I.1, -the main thread uses the global errno variable, and can therefore -execute code not compiled with -D_REENTRANT.

- -

I.6: SVGAlib doesn't work with LinuxThreads. Why? -

- -Because both LinuxThreads and SVGAlib use the signals -SIGUSR1 and SIGUSR2. See question H.4. -

- - -


-

- -

J. Signals and threads

- -

J.1: When it comes to signals, what is shared -between threads and what isn't?

- -Signal handlers are shared between all threads: when a thread calls -sigaction(), it sets how the signal is handled not only -for itself, but for all other threads in the program as well.

- -On the other hand, signal masks are per-thread: each thread chooses -which signals it blocks independently of others. At thread creation -time, the newly created thread inherits the signal mask of the thread -calling pthread_create(). But afterwards, the new thread -can modify its signal mask independently of its creator thread.

- -

J.2: When I send a SIGKILL to a -particular thread using pthread_kill, all my threads are -killed!

- -That's how it should be. The POSIX standard mandates that all threads -should terminate when the process (i.e. the collection of all threads -running the program) receives a signal whose effect is to -terminate the process (such as SIGKILL or SIGINT -when no handler is installed on that signal). This behavior makes a -lot of sense: when you type "ctrl-C" at the keyboard, or when a thread -crashes on a division by zero or a segmentation fault, you really want -all threads to stop immediately, not just the one that caused the -segmentation violation or that got the SIGINT signal. -(This assumes default behavior for those signals; see question -J.3 if you install handlers for those signals.)

- -If you're trying to terminate a thread without bringing the whole -process down, use pthread_cancel().

- -

J.3: I've installed a handler on a signal. Which -thread executes the handler when the signal is received?

- -If the signal is generated by a thread during its execution (e.g. a -thread executes a division by zero and thus generates a -SIGFPE signal), then the handler is executed by that -thread. This also applies to signals generated by -raise().

- -If the signal is sent to a particular thread using -pthread_kill(), then that thread executes the handler.

- -If the signal is sent via kill() or the tty interface -(e.g. by pressing ctrl-C), then the POSIX specs say that the handler -is executed by any thread in the process that does not currently block -the signal. In other terms, POSIX considers that the signal is sent -to the process (the collection of all threads) as a whole, and any -thread that is not blocking this signal can then handle it.

- -The latter case is where LinuxThreads departs from the POSIX specs. -In LinuxThreads, there is no real notion of ``the process as a whole'': -in the kernel, each thread is really a distinct process with a -distinct PID, and signals sent to the PID of a thread can only be -handled by that thread. As long as no thread is blocking the signal, -the behavior conforms to the standard: one (unspecified) thread of the -program handles the signal. But if the thread to which PID the signal -is sent blocks the signal, and some other thread does not block the -signal, then LinuxThreads will simply queue in -that thread and execute the handler only when that thread unblocks -the signal, instead of executing the handler immediately in the other -thread that does not block the signal.

- -This is to be viewed as a LinuxThreads bug, but I currently don't see -any way to implement the POSIX behavior without kernel support.

- -

J.3: How shall I go about mixing signals and threads -in my program?

- -The less you mix them, the better. Notice that all -pthread_* functions are not async-signal safe, meaning -that you should not call them from signal handlers. This -recommendation is not to be taken lightly: your program can deadlock -if you call a pthread_* function from a signal handler! -

- -The only sensible things you can do from a signal handler is set a -global flag, or call sem_post on a semaphore, to record -the delivery of the signal. The remainder of the program can then -either poll the global flag, or use sem_wait() and -sem_trywait() on the semaphore.

- -Another option is to do nothing in the signal handler, and dedicate -one thread (preferably the initial thread) to wait synchronously for -signals, using sigwait(), and send messages to the other -threads accordingly. - -

J.4: When one thread is blocked in -sigwait(), other threads no longer receive the signals -sigwait() is waiting for! What happens?

- -It's an unfortunate consequence of how LinuxThreads implements -sigwait(). Basically, it installs signal handlers on all -signals waited for, in order to record which signal was received. -Since signal handlers are shared with the other threads, this -temporarily deactivates any signal handlers you might have previously -installed on these signals.

- -Though surprising, this behavior actually seems to conform to the -POSIX standard. According to POSIX, sigwait() is -guaranteed to work as expected only if all other threads in the -program block the signals waited for (otherwise, the signals could be -delivered to other threads than the one doing sigwait(), -which would make sigwait() useless). In this particular -case, the problem described in this question does not appear.

- -One day, sigwait() will be implemented in the kernel, -along with others POSIX 1003.1b extensions, and sigwait() -will have a more natural behavior (as well as better performances).

- -


-

- -

K. Internals of LinuxThreads

- -

K.1: What is the implementation model for -LinuxThreads?

- -LinuxThreads follows the so-called "one-to-one" model: each thread is -actually a separate process in the kernel. The kernel scheduler takes -care of scheduling the threads, just like it schedules regular -processes. The threads are created with the Linux -clone() system call, which is a generalization of -fork() allowing the new process to share the memory -space, file descriptors, and signal handlers of the parent.

- -Advantages of the "one-to-one" model include: -

    -
  • minimal overhead on CPU-intensive multiprocessing (with -about one thread per processor); -
  • minimal overhead on I/O operations; -
  • a simple and robust implementation (the kernel scheduler does -most of the hard work for us). -
-The main disadvantage is more expensive context switches on mutex and -condition operations, which must go through the kernel. This is -mitigated by the fact that context switches in the Linux kernel are -pretty efficient.

- -

K.2: Have you considered other implementation -models?

- -There are basically two other models. The "many-to-one" model -relies on a user-level scheduler that context-switches between the -threads entirely in user code; viewed from the kernel, there is only -one process running. This model is completely out of the question for -me, since it does not take advantage of multiprocessors, and require -unholy magic to handle blocking I/O operations properly. There are -several user-level thread libraries available for Linux, but I found -all of them deficient in functionality, performance, and/or robustness. -

- -The "many-to-many" model combines both kernel-level and user-level -scheduling: several kernel-level threads run concurrently, each -executing a user-level scheduler that selects between user threads. -Most commercial Unix systems (Solaris, Digital Unix, IRIX) implement -POSIX threads this way. This model combines the advantages of both -the "many-to-one" and the "one-to-one" model, and is attractive -because it avoids the worst-case behaviors of both models -- -especially on kernels where context switches are expensive, such as -Digital Unix. Unfortunately, it is pretty complex to implement, and -requires kernel support which Linux does not provide. Linus Torvalds -and other Linux kernel developers have always been pushing the -"one-to-one" model in the name of overall simplicity, and are doing a -pretty good job of making kernel-level context switches between -threads efficient. LinuxThreads is just following the general -direction they set.

- -


-
Xavier.Leroy@inria.fr
- - diff --git a/libpthread/linuxthreads/LICENSE b/libpthread/linuxthreads/LICENSE deleted file mode 100644 index 7bcca6050..000000000 --- a/libpthread/linuxthreads/LICENSE +++ /dev/null @@ -1,501 +0,0 @@ -GNU LIBRARY GENERAL PUBLIC LICENSE -********************************** - - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 59 Temple Place -- Suite 330, Boston, MA 02111-1307, USA - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - [This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - -Preamble -======== - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it in -new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the library, or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link a program with the library, you must provide -complete object files to the recipients so that they can relink them -with the library, after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, so that any problems introduced by others will not reflect on -the original authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License, which was designed for utility -programs. This license, the GNU Library General Public License, -applies to certain designated libraries. This license is quite -different from the ordinary one; be sure to read it in full, and don't -assume that anything in it is the same as in the ordinary license. - - The reason we have a separate public license for some libraries is -that they blur the distinction we usually make between modifying or -adding to a program and simply using it. Linking a program with a -library, without changing the library, is in some sense simply using -the library, and is analogous to running a utility program or -application program. However, in a textual and legal sense, the linked -executable is a combined work, a derivative of the original library, -and the ordinary General Public License treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended -to permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to -achieve this as regards changes in header files, but we have achieved -it as regards changes in the actual functions of the Library.) The -hope is that this will lead to faster development of free libraries. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which - contains a notice placed by the copyright holder or other - authorized party saying it may be distributed under the terms of - this Library General Public License (also called "this License"). - Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data - prepared so as to be conveniently linked with application programs - (which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work - which has been distributed under these terms. A "work based on the - Library" means either the Library or any derivative work under - copyright law: that is to say, a work containing the Library or a - portion of it, either verbatim or with modifications and/or - translated straightforwardly into another language. (Hereinafter, - translation is included without limitation in the term - "modification".) - - "Source code" for a work means the preferred form of the work for - making modifications to it. For a library, complete source code - means all the source code for all modules it contains, plus any - associated interface definition files, plus the scripts used to - control compilation and installation of the library. - - Activities other than copying, distribution and modification are - not covered by this License; they are outside its scope. The act - of running a program using the Library is not restricted, and - output from such a program is covered only if its contents - constitute a work based on the Library (independent of the use of - the Library in a tool for writing it). Whether that is true - depends on what the Library does and what the program that uses - the Library does. - - 1. You may copy and distribute verbatim copies of the Library's - complete source code as you receive it, in any medium, provided - that you conspicuously and appropriately publish on each copy an - appropriate copyright notice and disclaimer of warranty; keep - intact all the notices that refer to this License and to the - absence of any warranty; and distribute a copy of this License - along with the Library. - - You may charge a fee for the physical act of transferring a copy, - and you may at your option offer warranty protection in exchange - for a fee. - - 2. You may modify your copy or copies of the Library or any portion - of it, thus forming a work based on the Library, and copy and - distribute such modifications or work under the terms of Section 1 - above, provided that you also meet all of these conditions: - - a. The modified work must itself be a software library. - - b. You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c. You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d. If a facility in the modified Library refers to a function or - a table of data to be supplied by an application program that - uses the facility, other than as an argument passed when the - facility is invoked, then you must make a good faith effort - to ensure that, in the event an application does not supply - such function or table, the facility still operates, and - performs whatever part of its purpose remains meaningful. - - (For example, a function in a library to compute square roots - has a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function - must be optional: if the application does not supply it, the - square root function must still compute square roots.) - - These requirements apply to the modified work as a whole. If - identifiable sections of that work are not derived from the - Library, and can be reasonably considered independent and separate - works in themselves, then this License, and its terms, do not - apply to those sections when you distribute them as separate - works. But when you distribute the same sections as part of a - whole which is a work based on the Library, the distribution of - the whole must be on the terms of this License, whose permissions - for other licensees extend to the entire whole, and thus to each - and every part regardless of who wrote it. - - Thus, it is not the intent of this section to claim rights or - contest your rights to work written entirely by you; rather, the - intent is to exercise the right to control the distribution of - derivative or collective works based on the Library. - - In addition, mere aggregation of another work not based on the - Library with the Library (or with a work based on the Library) on - a volume of a storage or distribution medium does not bring the - other work under the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public - License instead of this License to a given copy of the Library. - To do this, you must alter all the notices that refer to this - License, so that they refer to the ordinary GNU General Public - License, version 2, instead of to this License. (If a newer - version than version 2 of the ordinary GNU General Public License - has appeared, then you can specify that version instead if you - wish.) Do not make any other change in these notices. - - Once this change is made in a given copy, it is irreversible for - that copy, so the ordinary GNU General Public License applies to - all subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of - the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or - derivative of it, under Section 2) in object code or executable - form under the terms of Sections 1 and 2 above provided that you - accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software - interchange. - - If distribution of object code is made by offering access to copy - from a designated place, then offering equivalent access to copy - the source code from the same place satisfies the requirement to - distribute the source code, even though third parties are not - compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the - Library, but is designed to work with the Library by being - compiled or linked with it, is called a "work that uses the - Library". Such a work, in isolation, is not a derivative work of - the Library, and therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library - creates an executable that is a derivative of the Library (because - it contains portions of the Library), rather than a "work that - uses the library". The executable is therefore covered by this - License. Section 6 states terms for distribution of such - executables. - - When a "work that uses the Library" uses material from a header - file that is part of the Library, the object code for the work may - be a derivative work of the Library even though the source code is - not. Whether this is true is especially significant if the work - can be linked without the Library, or if the work is itself a - library. The threshold for this to be true is not precisely - defined by law. - - If such an object file uses only numerical parameters, data - structure layouts and accessors, and small macros and small inline - functions (ten lines or less in length), then the use of the object - file is unrestricted, regardless of whether it is legally a - derivative work. (Executables containing this object code plus - portions of the Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may - distribute the object code for the work under the terms of Section - 6. Any executables containing that work also fall under Section 6, - whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also compile or - link a "work that uses the Library" with the Library to produce a - work containing portions of the Library, and distribute that work - under terms of your choice, provided that the terms permit - modification of the work for the customer's own use and reverse - engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the - Library is used in it and that the Library and its use are covered - by this License. You must supply a copy of this License. If the - work during execution displays copyright notices, you must include - the copyright notice for the Library among them, as well as a - reference directing the user to the copy of this License. Also, - you must do one of these things: - - a. Accompany the work with the complete corresponding - machine-readable source code for the Library including - whatever changes were used in the work (which must be - distributed under Sections 1 and 2 above); and, if the work - is an executable linked with the Library, with the complete - machine-readable "work that uses the Library", as object code - and/or source code, so that the user can modify the Library - and then relink to produce a modified executable containing - the modified Library. (It is understood that the user who - changes the contents of definitions files in the Library will - not necessarily be able to recompile the application to use - the modified definitions.) - - b. Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - c. If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the - above specified materials from the same place. - - d. Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the - Library" must include any data and utility programs needed for - reproducing the executable from it. However, as a special - exception, the source code distributed need not include anything - that is normally distributed (in either source or binary form) - with the major components (compiler, kernel, and so on) of the - operating system on which the executable runs, unless that - component itself accompanies the executable. - - It may happen that this requirement contradicts the license - restrictions of other proprietary libraries that do not normally - accompany the operating system. Such a contradiction means you - cannot use both them and the Library together in an executable - that you distribute. - - 7. You may place library facilities that are a work based on the - Library side-by-side in a single library together with other - library facilities not covered by this License, and distribute - such a combined library, provided that the separate distribution - of the work based on the Library and of the other library - facilities is otherwise permitted, and provided that you do these - two things: - - a. Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b. Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same - work. - - 8. You may not copy, modify, sublicense, link with, or distribute the - Library except as expressly provided under this License. Any - attempt otherwise to copy, modify, sublicense, link with, or - distribute the Library is void, and will automatically terminate - your rights under this License. However, parties who have - received copies, or rights, from you under this License will not - have their licenses terminated so long as such parties remain in - full compliance. - - 9. You are not required to accept this License, since you have not - signed it. However, nothing else grants you permission to modify - or distribute the Library or its derivative works. These actions - are prohibited by law if you do not accept this License. - Therefore, by modifying or distributing the Library (or any work - based on the Library), you indicate your acceptance of this - License to do so, and all its terms and conditions for copying, - distributing or modifying the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the - Library), the recipient automatically receives a license from the - original licensor to copy, distribute, link with or modify the - Library subject to these terms and conditions. You may not impose - any further restrictions on the recipients' exercise of the rights - granted herein. You are not responsible for enforcing compliance - by third parties to this License. - - 11. If, as a consequence of a court judgment or allegation of patent - infringement or for any other reason (not limited to patent - issues), conditions are imposed on you (whether by court order, - agreement or otherwise) that contradict the conditions of this - License, they do not excuse you from the conditions of this - License. If you cannot distribute so as to satisfy simultaneously - your obligations under this License and any other pertinent - obligations, then as a consequence you may not distribute the - Library at all. For example, if a patent license would not permit - royalty-free redistribution of the Library by all those who - receive copies directly or indirectly through you, then the only - way you could satisfy both it and this License would be to refrain - entirely from distribution of the Library. - - If any portion of this section is held invalid or unenforceable - under any particular circumstance, the balance of the section is - intended to apply, and the section as a whole is intended to apply - in other circumstances. - - It is not the purpose of this section to induce you to infringe any - patents or other property right claims or to contest validity of - any such claims; this section has the sole purpose of protecting - the integrity of the free software distribution system which is - implemented by public license practices. Many people have made - generous contributions to the wide range of software distributed - through that system in reliance on consistent application of that - system; it is up to the author/donor to decide if he or she is - willing to distribute software through any other system and a - licensee cannot impose that choice. - - This section is intended to make thoroughly clear what is believed - to be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in - certain countries either by patents or by copyrighted interfaces, - the original copyright holder who places the Library under this - License may add an explicit geographical distribution limitation - excluding those countries, so that distribution is permitted only - in or among countries not thus excluded. In such case, this - License incorporates the limitation as if written in the body of - this License. - - 13. The Free Software Foundation may publish revised and/or new - versions of the Library General Public License from time to time. - Such new versions will be similar in spirit to the present version, - but may differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the - Library specifies a version number of this License which applies - to it and "any later version", you have the option of following - the terms and conditions either of that version or of any later - version published by the Free Software Foundation. If the Library - does not specify a license version number, you may choose any - version ever published by the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free - programs whose distribution conditions are incompatible with these, - write to the author to ask for permission. For software which is - copyrighted by the Free Software Foundation, write to the Free - Software Foundation; we sometimes make exceptions for this. Our - decision will be guided by the two goals of preserving the free - status of all derivatives of our free software and of promoting - the sharing and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO - WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE - LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT - HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT - WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT - NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE - QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE - LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY - SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN - WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY - MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE - LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, - INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR - INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF - DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU - OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY - OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Libraries -============================================== - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of -the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -It is safest to attach them to the start of each source file to most -effectively convey the exclusion of warranty; and each file should have -at least the "copyright" line and a pointer to where the full notice is -found. - - ONE LINE TO GIVE THE LIBRARY'S NAME AND AN IDEA OF WHAT IT DOES. - Copyright (C) YEAR NAME OF AUTHOR - - This library is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2 of the License, or (at - your option) any later version. - - This library is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - - Also add information on how to contact you by electronic and paper -mail. - - You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the library - `Frob' (a library for tweaking knobs) written by James Random Hacker. - - SIGNATURE OF TY COON, 1 April 1990 - Ty Coon, President of Vice - - That's all there is to it! - diff --git a/libpthread/linuxthreads/Makefile b/libpthread/linuxthreads/Makefile deleted file mode 100644 index f92f205a5..000000000 --- a/libpthread/linuxthreads/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# Makefile for uClibc -# -# Copyright (C) 2000-2005 Erik Andersen -# -# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. -# - -TOPDIR=../../ - -top_srcdir=$(TOPDIR) -top_builddir=../../ -include $(top_builddir)Rules.mak -all: libs -include Makefile.in -include $(top_srcdir)Makerules diff --git a/libpthread/linuxthreads/Makefile.in b/libpthread/linuxthreads/Makefile.in deleted file mode 100644 index 4804a73c2..000000000 --- a/libpthread/linuxthreads/Makefile.in +++ /dev/null @@ -1,62 +0,0 @@ -# Makefile for uClibc -# -# Copyright (C) 2003 Paul Mundt -# Copyright (C) 2000-2005 Erik Andersen -# -# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. -# - -CFLAGS+=$(SSP_ALL_CFLAGS) - -# This stuff will not compile without at least -O1 -CFLAGS:=$(CFLAGS:-O0=-O1) - -LDFLAGS:=$(LDFLAGS_NOSTRIP) - -ifeq ($(UCLIBC_CTOR_DTOR),y) -SHARED_START_FILES:=$(top_builddir)lib/crti.o $(LIBGCC_DIR)crtbeginS.o -SHARED_END_FILES:=$(LIBGCC_DIR)crtendS.o $(top_builddir)lib/crtn.o -endif - -ifeq ($(PTHREADS_DEBUG_SUPPORT),y) -STRIP_FLAGS:=-X --strip-debug -R .note -R .comment -endif - -DOMULTI=n - -LIB_NAME:=libpthread - -libpthread_DIR:=$(top_srcdir)libpthread/linuxthreads -libpthread_OUT:=$(top_builddir)libpthread/linuxthreads - -ARCH_CFLAGS:=$(CFLAGS) --include $(libpthread_DIR)/sysdeps/$(TARGET_ARCH)/Makefile.arch -CFLAGS:=$(ARCH_CFLAGS) - -libpthread_SRC:=$(wildcard $(libpthread_DIR)/*.c) -ifneq ($(UCLIBC_HAS_XLOCALE),y) -libpthread_SRC:=$(filter-out $(libpthread_DIR)/locale.c,$(libpthread_SRC)) -endif - -ifneq ($(DOMULTI),n) -libpthread_NO_MULTI:=manager.c pt-machine.c -libpthread_SRC:=$(filter-out $(patsubst %.c,$(libpthread_DIR)/%.c,$(libpthread_NO_MULTI)),$(libpthread_SRC)) -endif - -# remove generic sources, if arch specific version is present -ifneq ($(strip $(libpthread_ARCH_SRC)),) -libpthread_SRC:=$(filter-out $(patsubst %.c,$(libpthread_DIR)/%.c,$(notdir $(libpthread_ARCH_SRC))),$(libpthread_SRC)) -endif - -libpthread_OBJ:=$(patsubst $(libpthread_DIR)/%.c,$(libpthread_OUT)/%.o,$(libpthread_SRC)) - -libpthread-a-$(UCLIBC_HAS_THREADS)+=$(libpthread_OBJ) -libpthread-so-$(UCLIBC_HAS_THREADS)+=$(libpthread_OBJ:.o=.os) - -libpthread-multi-$(UCLIBC_HAS_THREADS)+=$(libpthread_SRC) -libpthread-nomulti-$(UCLIBC_HAS_THREADS)+=$(patsubst %.c,$(libpthread_OUT)/%.o,$(libpthread_NO_MULTI)) - -objclean-y+=libpthread_clean - -lib-a-$(UCLIBC_HAS_THREADS)+=$(top_builddir)lib/libpthread.a -lib-so-$(UCLIBC_HAS_THREADS)+=$(top_builddir)lib/libpthread.so diff --git a/libpthread/linuxthreads/README b/libpthread/linuxthreads/README deleted file mode 100644 index 955bd59e7..000000000 --- a/libpthread/linuxthreads/README +++ /dev/null @@ -1,166 +0,0 @@ - Linuxthreads - POSIX 1003.1c kernel threads for Linux - - Copyright 1996, 1997 Xavier Leroy (Xavier.Leroy@inria.fr) - - -DESCRIPTION: - -This is release 0.7 (late beta) of LinuxThreads, a BiCapitalized -implementation of the Posix 1003.1c "pthread" interface for Linux. - -LinuxThreads provides kernel-level threads: each thread is a separate -Unix process, sharing its address space with the other threads through -the new system call clone(). Scheduling between threads is handled by -the kernel scheduler, just like scheduling between Unix processes. - - -REQUIREMENTS: - -- Linux version 2.0 and up (requires the new clone() system call - and the new realtime scheduler). - -- For Intel platforms: libc 5.2.18 or later is required. - 5.2.18 or 5.4.12 or later are recommended; - 5.3.12 and 5.4.7 have problems (see the FAQ.html file for more info). - -- Also supports glibc 2 (a.k.a. libc 6), which actually comes with - a specially-adapted version of this library. - -- Currently supports Intel, Alpha, Sparc, Motorola 68k, ARM and MIPS - platforms. - -- Multiprocessors are supported. - - -INSTALLATION: - -- Edit the Makefile, set the variables in the "Configuration" section. - -- Do "make". - -- Do "make install". - - -USING LINUXTHREADS: - - gcc -D_REENTRANT ... -lpthread - -A complete set of manual pages is included. Also see the subdirectory -Examples/ for some sample programs. - - -STATUS: - -- All functions in the Posix 1003.1c base interface implemented. - Also supports priority scheduling. - -- For users of libc 5 (H.J.Lu's libc), a number of C library functions - are reimplemented or wrapped to make them thread-safe, including: - * malloc functions - * stdio functions (define _REENTRANT before including ) - * per-thread errno variable (define _REENTRANT before including ) - * directory reading functions (opendir(), etc) - * sleep() - * gmtime(), localtime() - - New library functions provided: - * flockfile(), funlockfile(), ftrylockfile() - * reentrant versions of network database functions (gethostbyname_r(), etc) - and password functions (getpwnam_r(), etc). - -- libc 6 (glibc 2) provides much better thread support than libc 5, - and comes with a specially-adapted version of LinuxThreads. - For serious multithreaded programming, you should consider switching - to glibc 2. It is available from ftp.gnu.org:/pub/gnu and its mirrors. - - -WARNING: - -Many existing libraries are not compatible with LinuxThreads, -either because they are not inherently thread-safe, or because they -have not been compiled with the -D_REENTRANT. For more info, see the -FAQ.html file in this directory. - -A prime example of the latter is Xlib. If you link it with -LinuxThreads, you'll probably get an "unknown 0 error" very -early. This is just a consequence of the Xlib binaries using the -global variable "errno" to fetch error codes, while LinuxThreads and -the C library use the per-thread "errno" location. - -See the file README.Xfree3.3 for info on how to compile the Xfree 3.3 -libraries to make them compatible with LinuxThreads. - - -KNOWN BUGS AND LIMITATIONS: - -- Threads share pretty much everything they should share according - to the standard: memory space, file descriptors, signal handlers, - current working directory, etc. One thing that they do not share - is their pid's and parent pid's. According to the standard, they - should have the same, but that's one thing we cannot achieve - in this implementation (until the CLONE_PID flag to clone() becomes - usable). - -- The current implementation uses the two signals SIGUSR1 and SIGUSR2, - so user-level code cannot employ them. Ideally, there should be two - signals reserved for this library. One signal is used for restarting - threads blocked on mutexes or conditions; the other is for thread - cancellation. - - *** This is not anymore true when the application runs on a kernel - newer than approximately 2.1.60. - -- The stacks for the threads are allocated high in the memory space, - below the stack of the initial process, and spaced 2M apart. - Stacks are allocated with the "grow on demand" flag, so they don't - use much virtual space initially (4k, currently), but can grow - up to 2M if needed. - - Reserving such a large address space for each thread means that, - on a 32-bit architecture, no more than about 1000 threads can - coexist (assuming a 2Gb address space for user processes), - but this is reasonable, since each thread uses up one entry in the - kernel's process table, which is usually limited to 512 processes. - - Another potential problem of the "grow on demand" scheme is that - nothing prevents the user from mmap'ing something in the 2M address - window reserved for a thread stack, possibly causing later extensions of - that stack to fail. Mapping at fixed addresses should be avoided - when using this library. - -- Signal handling does not fully conform to the Posix standard, - due to the fact that threads are here distinct processes that can be - sent signals individually, so there's no notion of sending a signal - to "the" process (the collection of all threads). - More precisely, here is a summary of the standard requirements - and how they are met by the implementation: - - 1- Synchronous signals (generated by the thread execution, e.g. SIGFPE) - are delivered to the thread that raised them. - (OK.) - - 2- A fatal asynchronous signal terminates all threads in the process. - (OK. The thread manager notices when a thread dies on a signal - and kills all other threads with the same signal.) - - 3- An asynchronous signal will be delivered to one of the threads - of the program which does not block the signal (it is unspecified - which). - (No, the signal is delivered to the thread it's been sent to, - based on the pid of the thread. If that thread is currently - blocking the signal, the signal remains pending.) - - 4- The signal will be delivered to at most one thread. - (OK, except for signals generated from the terminal or sent to - the process group, which will be delivered to all threads.) - -- The current implementation of the MIPS support assumes a MIPS ISA II - processor or better. These processors support atomic operations by - ll/sc instructions. Older R2000/R3000 series processors are not - supported yet; support for these will have higher overhead. - -- The current implementation of the ARM support assumes that the SWP - (atomic swap register with memory) instruction is available. This is - the case for all processors except for the ARM1 and ARM2. On StrongARM, - the SWP instruction does not bypass the cache, so multi-processor support - will be more troublesome. diff --git a/libpthread/linuxthreads/attr.c b/libpthread/linuxthreads/attr.c deleted file mode 100644 index 4432a04d1..000000000 --- a/libpthread/linuxthreads/attr.c +++ /dev/null @@ -1,214 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* changed for uClibc */ -#define __sched_get_priority_min sched_get_priority_min -#define __sched_get_priority_max sched_get_priority_max - -/* Handling of thread attributes */ - -#include -#include -#include -#include -#include "pthread.h" -#include "internals.h" - -extern int __getpagesize(void); - -/* NOTE: With uClibc I don't think we need this versioning stuff. - * Therefore, define the function pthread_attr_init() here using - * a strong symbol. */ - -//int __pthread_attr_init_2_1(pthread_attr_t *attr) -int pthread_attr_init(pthread_attr_t *attr) -{ - size_t ps = __getpagesize (); - - attr->__detachstate = PTHREAD_CREATE_JOINABLE; - attr->__schedpolicy = SCHED_OTHER; - attr->__schedparam.sched_priority = 0; - attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; - attr->__scope = PTHREAD_SCOPE_SYSTEM; - attr->__guardsize = ps; - attr->__stackaddr = NULL; - attr->__stackaddr_set = 0; - attr->__stacksize = STACK_SIZE - ps; - return 0; -} - -/* uClibc: leave out this for now. */ -#if DO_PTHREAD_VERSIONING_WITH_UCLIBC -#if defined __HAVE_ELF__ && defined __PIC__ && defined DO_VERSIONING -default_symbol_version (__pthread_attr_init_2_1, pthread_attr_init, GLIBC_2.1); - -int __pthread_attr_init_2_0(pthread_attr_t *attr) -{ - attr->__detachstate = PTHREAD_CREATE_JOINABLE; - attr->__schedpolicy = SCHED_OTHER; - attr->__schedparam.sched_priority = 0; - attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; - attr->__scope = PTHREAD_SCOPE_SYSTEM; - return 0; -} -symbol_version (__pthread_attr_init_2_0, pthread_attr_init, GLIBC_2.0); -#else -strong_alias (__pthread_attr_init_2_1, pthread_attr_init) -#endif -#endif /* DO_PTHREAD_VERSIONING_WITH_UCLIBC */ - -int pthread_attr_destroy(pthread_attr_t *attr) -{ - return 0; -} - -int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) -{ - if (detachstate < PTHREAD_CREATE_JOINABLE || - detachstate > PTHREAD_CREATE_DETACHED) - return EINVAL; - attr->__detachstate = detachstate; - return 0; -} - -int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) -{ - *detachstate = attr->__detachstate; - return 0; -} - -int pthread_attr_setschedparam(pthread_attr_t *attr, - const struct sched_param *param) -{ - int max_prio = __sched_get_priority_max(attr->__schedpolicy); - int min_prio = __sched_get_priority_min(attr->__schedpolicy); - - if (param->sched_priority < min_prio || param->sched_priority > max_prio) - return EINVAL; - memcpy (&attr->__schedparam, param, sizeof (struct sched_param)); - return 0; -} - -int pthread_attr_getschedparam(const pthread_attr_t *attr, - struct sched_param *param) -{ - memcpy (param, &attr->__schedparam, sizeof (struct sched_param)); - return 0; -} - -int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) -{ - if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR) - return EINVAL; - attr->__schedpolicy = policy; - return 0; -} - -int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) -{ - *policy = attr->__schedpolicy; - return 0; -} - -int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) -{ - if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED) - return EINVAL; - attr->__inheritsched = inherit; - return 0; -} - -int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) -{ - *inherit = attr->__inheritsched; - return 0; -} - -int pthread_attr_setscope(pthread_attr_t *attr, int scope) -{ - switch (scope) { - case PTHREAD_SCOPE_SYSTEM: - attr->__scope = scope; - return 0; - case PTHREAD_SCOPE_PROCESS: - return ENOTSUP; - default: - return EINVAL; - } -} - -int pthread_attr_getscope(const pthread_attr_t *attr, int *scope) -{ - *scope = attr->__scope; - return 0; -} - -int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) -{ - size_t ps = __getpagesize (); - - /* First round up the guard size. */ - guardsize = roundup (guardsize, ps); - - /* The guard size must not be larger than the stack itself */ - if (guardsize >= attr->__stacksize) return EINVAL; - - attr->__guardsize = guardsize; - - return 0; -} -weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize) - -int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) -{ - *guardsize = attr->__guardsize; - return 0; -} -weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize) - -int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) -{ - attr->__stackaddr = stackaddr; - attr->__stackaddr_set = 1; - return 0; -} -weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr) - -int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) -{ - /* XXX This function has a stupid definition. The standard specifies - no error value but what is if no stack address was set? We simply - return the value we have in the member. */ - *stackaddr = attr->__stackaddr; - return 0; -} -weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr) - -int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) -{ - /* We don't accept value smaller than PTHREAD_STACK_MIN. */ - if (stacksize < PTHREAD_STACK_MIN) - return EINVAL; - - attr->__stacksize = stacksize; - return 0; -} -weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize) - -int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) -{ - *stacksize = attr->__stacksize; - return 0; -} -weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize) diff --git a/libpthread/linuxthreads/cancel.c b/libpthread/linuxthreads/cancel.c deleted file mode 100644 index 1356348a7..000000000 --- a/libpthread/linuxthreads/cancel.c +++ /dev/null @@ -1,184 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Thread cancellation */ - -#define __FORCE_GLIBC -#include -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "restart.h" -#ifdef __UCLIBC_HAS_RPC__ -#include -extern void __rpc_thread_destroy(void); -#endif - - -int pthread_setcancelstate(int state, int * oldstate) -{ - pthread_descr self = thread_self(); - if (state < PTHREAD_CANCEL_ENABLE || state > PTHREAD_CANCEL_DISABLE) - return EINVAL; - if (oldstate != NULL) *oldstate = THREAD_GETMEM(self, p_cancelstate); - THREAD_SETMEM(self, p_cancelstate, state); - if (THREAD_GETMEM(self, p_canceled) && - THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && - THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) - pthread_exit(PTHREAD_CANCELED); - return 0; -} - -int pthread_setcanceltype(int type, int * oldtype) -{ - pthread_descr self = thread_self(); - if (type < PTHREAD_CANCEL_DEFERRED || type > PTHREAD_CANCEL_ASYNCHRONOUS) - return EINVAL; - if (oldtype != NULL) *oldtype = THREAD_GETMEM(self, p_canceltype); - THREAD_SETMEM(self, p_canceltype, type); - if (THREAD_GETMEM(self, p_canceled) && - THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && - THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) - pthread_exit(PTHREAD_CANCELED); - return 0; -} - -int pthread_cancel(pthread_t thread) -{ - pthread_handle handle = thread_handle(thread); - int pid; - int dorestart = 0; - pthread_descr th; - pthread_extricate_if *pextricate; - - __pthread_lock(&handle->h_lock, NULL); - if (invalid_handle(handle, thread)) { - __pthread_unlock(&handle->h_lock); - return ESRCH; - } - - th = handle->h_descr; - - if (th->p_canceled) { - __pthread_unlock(&handle->h_lock); - return 0; - } - - pextricate = th->p_extricate; - th->p_canceled = 1; - pid = th->p_pid; - - /* If the thread has registered an extrication interface, then - invoke the interface. If it returns 1, then we succeeded in - dequeuing the thread from whatever waiting object it was enqueued - with. In that case, it is our responsibility to wake it up. - And also to set the p_woken_by_cancel flag so the woken thread - can tell that it was woken by cancellation. */ - - if (pextricate != NULL) { - dorestart = pextricate->pu_extricate_func(pextricate->pu_object, th); - th->p_woken_by_cancel = dorestart; - } - - __pthread_unlock(&handle->h_lock); - - /* If the thread has suspended or is about to, then we unblock it by - issuing a restart, instead of a cancel signal. Otherwise we send - the cancel signal to unblock the thread from a cancellation point, - or to initiate asynchronous cancellation. The restart is needed so - we have proper accounting of restarts; suspend decrements the thread's - resume count, and restart() increments it. This also means that suspend's - handling of the cancel signal is obsolete. */ - - if (dorestart) - restart(th); - else - kill(pid, __pthread_sig_cancel); - - return 0; -} - -void pthread_testcancel(void) -{ - pthread_descr self = thread_self(); - if (THREAD_GETMEM(self, p_canceled) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) - pthread_exit(PTHREAD_CANCELED); -} - -void _pthread_cleanup_push(struct _pthread_cleanup_buffer * buffer, - void (*routine)(void *), void * arg) -{ - pthread_descr self = thread_self(); - buffer->__routine = routine; - buffer->__arg = arg; - buffer->__prev = THREAD_GETMEM(self, p_cleanup); - THREAD_SETMEM(self, p_cleanup, buffer); -} - -void _pthread_cleanup_pop(struct _pthread_cleanup_buffer * buffer, - int execute) -{ - pthread_descr self = thread_self(); - if (execute) buffer->__routine(buffer->__arg); - THREAD_SETMEM(self, p_cleanup, buffer->__prev); -} - -void _pthread_cleanup_push_defer(struct _pthread_cleanup_buffer * buffer, - void (*routine)(void *), void * arg) -{ - pthread_descr self = thread_self(); - buffer->__routine = routine; - buffer->__arg = arg; - buffer->__canceltype = THREAD_GETMEM(self, p_canceltype); - buffer->__prev = THREAD_GETMEM(self, p_cleanup); - THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED); - THREAD_SETMEM(self, p_cleanup, buffer); -} - -void _pthread_cleanup_pop_restore(struct _pthread_cleanup_buffer * buffer, - int execute) -{ - pthread_descr self = thread_self(); - if (execute) buffer->__routine(buffer->__arg); - THREAD_SETMEM(self, p_cleanup, buffer->__prev); - THREAD_SETMEM(self, p_canceltype, buffer->__canceltype); - if (THREAD_GETMEM(self, p_canceled) && - THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE && - THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) - pthread_exit(PTHREAD_CANCELED); -} - -void __pthread_perform_cleanup(void) -{ - pthread_descr self = thread_self(); - struct _pthread_cleanup_buffer * c; - for (c = THREAD_GETMEM(self, p_cleanup); c != NULL; c = c->__prev) - c->__routine(c->__arg); - -#ifdef __UCLIBC_HAS_RPC__ - /* And the TSD which needs special help. */ - if (THREAD_GETMEM(self, p_libc_specific[_LIBC_TSD_KEY_RPC_VARS]) != NULL) - __rpc_thread_destroy (); -#endif -} - -#ifndef __PIC__ -/* We need a hook to force the cancelation wrappers to be linked in when - static libpthread is used. */ -extern const int __pthread_provide_wrappers; -static const int * const __pthread_require_wrappers = - &__pthread_provide_wrappers; -#endif diff --git a/libpthread/linuxthreads/condvar.c b/libpthread/linuxthreads/condvar.c deleted file mode 100644 index f9c46a331..000000000 --- a/libpthread/linuxthreads/condvar.c +++ /dev/null @@ -1,296 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* and Pavel Krauz (krauz@fsid.cvut.cz). */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Condition variables */ - -#include -#include -#include -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "queue.h" -#include "restart.h" - -int pthread_cond_init(pthread_cond_t *cond, - const pthread_condattr_t *cond_attr) -{ - __pthread_init_lock(&cond->__c_lock); - cond->__c_waiting = NULL; - return 0; -} - -int pthread_cond_destroy(pthread_cond_t *cond) -{ - if (cond->__c_waiting != NULL) return EBUSY; - return 0; -} - -/* Function called by pthread_cancel to remove the thread from - waiting on a condition variable queue. */ - -static int cond_extricate_func(void *obj, pthread_descr th) -{ - volatile pthread_descr self = thread_self(); - pthread_cond_t *cond = obj; - int did_remove = 0; - - __pthread_lock(&cond->__c_lock, self); - did_remove = remove_from_queue(&cond->__c_waiting, th); - __pthread_unlock(&cond->__c_lock); - - return did_remove; -} - -int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - volatile pthread_descr self = thread_self(); - pthread_extricate_if extr; - int already_canceled = 0; - int spurious_wakeup_count; - - /* Check whether the mutex is locked and owned by this thread. */ - if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP - && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP - && mutex->__m_owner != self) - return EINVAL; - - /* Set up extrication interface */ - extr.pu_object = cond; - extr.pu_extricate_func = cond_extricate_func; - - /* Register extrication interface */ - THREAD_SETMEM(self, p_condvar_avail, 0); - __pthread_set_own_extricate_if(self, &extr); - - /* Atomically enqueue thread for waiting, but only if it is not - canceled. If the thread is canceled, then it will fall through the - suspend call below, and then call pthread_exit without - having to worry about whether it is still on the condition variable queue. - This depends on pthread_cancel setting p_canceled before calling the - extricate function. */ - - __pthread_lock(&cond->__c_lock, self); - if (!(THREAD_GETMEM(self, p_canceled) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) - enqueue(&cond->__c_waiting, self); - else - already_canceled = 1; - __pthread_unlock(&cond->__c_lock); - - if (already_canceled) { - __pthread_set_own_extricate_if(self, 0); - pthread_exit(PTHREAD_CANCELED); - } - - pthread_mutex_unlock(mutex); - - spurious_wakeup_count = 0; - while (1) - { - suspend(self); - if (THREAD_GETMEM(self, p_condvar_avail) == 0 - && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 - || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) - { - /* Count resumes that don't belong to us. */ - spurious_wakeup_count++; - continue; - } - break; - } - - __pthread_set_own_extricate_if(self, 0); - - /* Check for cancellation again, to provide correct cancellation - point behavior */ - - if (THREAD_GETMEM(self, p_woken_by_cancel) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { - THREAD_SETMEM(self, p_woken_by_cancel, 0); - pthread_mutex_lock(mutex); - pthread_exit(PTHREAD_CANCELED); - } - - /* Put back any resumes we caught that don't belong to us. */ - while (spurious_wakeup_count--) - restart(self); - - pthread_mutex_lock(mutex); - return 0; -} - -static int -pthread_cond_timedwait_relative(pthread_cond_t *cond, - pthread_mutex_t *mutex, - const struct timespec * abstime) -{ - volatile pthread_descr self = thread_self(); - int already_canceled = 0; - pthread_extricate_if extr; - int spurious_wakeup_count; - - /* Check whether the mutex is locked and owned by this thread. */ - if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP - && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP - && mutex->__m_owner != self) - return EINVAL; - - /* Set up extrication interface */ - extr.pu_object = cond; - extr.pu_extricate_func = cond_extricate_func; - - /* Register extrication interface */ - THREAD_SETMEM(self, p_condvar_avail, 0); - __pthread_set_own_extricate_if(self, &extr); - - /* Enqueue to wait on the condition and check for cancellation. */ - __pthread_lock(&cond->__c_lock, self); - if (!(THREAD_GETMEM(self, p_canceled) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) - enqueue(&cond->__c_waiting, self); - else - already_canceled = 1; - __pthread_unlock(&cond->__c_lock); - - if (already_canceled) { - __pthread_set_own_extricate_if(self, 0); - pthread_exit(PTHREAD_CANCELED); - } - - pthread_mutex_unlock(mutex); - - spurious_wakeup_count = 0; - while (1) - { - if (!timedsuspend(self, abstime)) { - int was_on_queue; - - /* __pthread_lock will queue back any spurious restarts that - may happen to it. */ - - __pthread_lock(&cond->__c_lock, self); - was_on_queue = remove_from_queue(&cond->__c_waiting, self); - __pthread_unlock(&cond->__c_lock); - - if (was_on_queue) { - __pthread_set_own_extricate_if(self, 0); - pthread_mutex_lock(mutex); - return ETIMEDOUT; - } - - /* Eat the outstanding restart() from the signaller */ - suspend(self); - } - - if (THREAD_GETMEM(self, p_condvar_avail) == 0 - && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 - || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) - { - /* Count resumes that don't belong to us. */ - spurious_wakeup_count++; - continue; - } - break; - } - - __pthread_set_own_extricate_if(self, 0); - - /* The remaining logic is the same as in other cancellable waits, - such as pthread_join sem_wait or pthread_cond wait. */ - - if (THREAD_GETMEM(self, p_woken_by_cancel) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { - THREAD_SETMEM(self, p_woken_by_cancel, 0); - pthread_mutex_lock(mutex); - pthread_exit(PTHREAD_CANCELED); - } - - /* Put back any resumes we caught that don't belong to us. */ - while (spurious_wakeup_count--) - restart(self); - - pthread_mutex_lock(mutex); - return 0; -} - -int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - const struct timespec * abstime) -{ - /* Indirect call through pointer! */ - return pthread_cond_timedwait_relative(cond, mutex, abstime); -} - -int pthread_cond_signal(pthread_cond_t *cond) -{ - pthread_descr th; - - __pthread_lock(&cond->__c_lock, NULL); - th = dequeue(&cond->__c_waiting); - __pthread_unlock(&cond->__c_lock); - if (th != NULL) { - th->p_condvar_avail = 1; - WRITE_MEMORY_BARRIER(); - restart(th); - } - return 0; -} - -int pthread_cond_broadcast(pthread_cond_t *cond) -{ - pthread_descr tosignal, th; - - __pthread_lock(&cond->__c_lock, NULL); - /* Copy the current state of the waiting queue and empty it */ - tosignal = cond->__c_waiting; - cond->__c_waiting = NULL; - __pthread_unlock(&cond->__c_lock); - /* Now signal each process in the queue */ - while ((th = dequeue(&tosignal)) != NULL) { - th->p_condvar_avail = 1; - WRITE_MEMORY_BARRIER(); - restart(th); - } - return 0; -} - -int pthread_condattr_init(pthread_condattr_t *attr) -{ - return 0; -} - -int pthread_condattr_destroy(pthread_condattr_t *attr) -{ - return 0; -} - -int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) -{ - *pshared = PTHREAD_PROCESS_PRIVATE; - return 0; -} - -int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) -{ - if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) - return EINVAL; - - /* For now it is not possible to shared a conditional variable. */ - if (pshared != PTHREAD_PROCESS_PRIVATE) - return ENOSYS; - - return 0; -} diff --git a/libpthread/linuxthreads/debug.h b/libpthread/linuxthreads/debug.h deleted file mode 100644 index a2ac5113a..000000000 --- a/libpthread/linuxthreads/debug.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** NAME: -** debug.h -** -** DESCRIPTION: -** This header file defines the debug macros used in pthreads. To turn -** debugging on, add -DDEBUG_PT to CFLAGS. It was added to the original -** distribution of linuxthreads. -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU Library General Public License -** as published by the Free Software Foundation; either version 2 -** of the License, or (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU Library General Public License for more details. -** -****************************************************************************/ - -#ifndef _PT_DEBUG_H -#define _PT_DEBUG_H - -#include - -#ifdef __DODEBUG_PT__ -# define DEBUG_PT -#endif - -/* include asserts for now */ -#define DO_ASSERT - -/* define the PDEBUG macro here */ -#undef PDEBUG -#ifdef DEBUG_PT -# define PDEBUG(fmt, args...) __pthread_message("%s: " fmt, __FUNCTION__, ## args) -#else -# define PDEBUG(fmt, args...) /* debug switched off */ -#endif - -/* nothing; placeholder to disable a PDEBUG message but don't delete it */ -#undef PDEBUGG -#define PDEBUGG(fmt, args...) - -/* Define ASSERT to stop/warn. Should be void in production code */ -#undef ASSERT -#ifdef DO_ASSERT -# define ASSERT(x) if (!(x)) fprintf(stderr, "pt: assertion failed in %s:%i.\n",\ - __FILE__, __LINE__) -#else -# define ASSERT(x) -#endif - -#endif /* _PT_DEBUG_H */ diff --git a/libpthread/linuxthreads/errno.c b/libpthread/linuxthreads/errno.c deleted file mode 100644 index f5778f98a..000000000 --- a/libpthread/linuxthreads/errno.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Define the location of errno for the remainder of the C library */ - -#define __FORCE_GLIBC -#include -#include -#include -#include "pthread.h" -#include "internals.h" -#include - -int * -__errno_location (void) -{ - pthread_descr self = thread_self(); - return THREAD_GETMEM (self, p_errnop); -} - -int * -__h_errno_location (void) -{ - pthread_descr self = thread_self(); - return THREAD_GETMEM (self, p_h_errnop); -} diff --git a/libpthread/linuxthreads/events.c b/libpthread/linuxthreads/events.c deleted file mode 100644 index a4bf1f898..000000000 --- a/libpthread/linuxthreads/events.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Event functions used while debugging. - Copyright (C) 1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* The functions contained here do nothing, they just return. */ - -#include "internals.h" - -void -__linuxthreads_create_event (void) -{ -} - -void -__linuxthreads_death_event (void) -{ -} - -void -__linuxthreads_reap_event (void) -{ -} diff --git a/libpthread/linuxthreads/internals.h b/libpthread/linuxthreads/internals.h deleted file mode 100644 index 50a4d2d59..000000000 --- a/libpthread/linuxthreads/internals.h +++ /dev/null @@ -1,518 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -#ifndef _INTERNALS_H -#define _INTERNALS_H 1 - -/* Internal data structures */ - -/* Includes */ - -#include /* for _LIBC_TSD_KEY_N */ -#include -#include -#include -#include -#include -#include "pt-machine.h" -#include "semaphore.h" -#include "../linuxthreads_db/thread_dbP.h" -#ifdef __UCLIBC_HAS_XLOCALE__ -#include -#endif /* __UCLIBC_HAS_XLOCALE__ */ - -/* Use a funky version in a probably vein attempt at preventing gdb - * from dlopen()'ing glibc's libthread_db library... */ -#define STRINGIFY(s) STRINGIFY2 (s) -#define STRINGIFY2(s) #s -#define VERSION STRINGIFY(__UCLIBC_MAJOR__) "." STRINGIFY(__UCLIBC_MINOR__) "." STRINGIFY(__UCLIBC_SUBLEVEL__) - -#ifndef THREAD_GETMEM -# define THREAD_GETMEM(descr, member) descr->member -#endif -#ifndef THREAD_GETMEM_NC -# define THREAD_GETMEM_NC(descr, member) descr->member -#endif -#ifndef THREAD_SETMEM -# define THREAD_SETMEM(descr, member, value) descr->member = (value) -#endif -#ifndef THREAD_SETMEM_NC -# define THREAD_SETMEM_NC(descr, member, value) descr->member = (value) -#endif - -/* Arguments passed to thread creation routine */ - -struct pthread_start_args { - void * (*start_routine)(void *); /* function to run */ - void * arg; /* its argument */ - sigset_t mask; /* initial signal mask for thread */ - int schedpolicy; /* initial scheduling policy (if any) */ - struct sched_param schedparam; /* initial scheduling parameters (if any) */ -}; - - -/* We keep thread specific data in a special data structure, a two-level - array. The top-level array contains pointers to dynamically allocated - arrays of a certain number of data pointers. So we can implement a - sparse array. Each dynamic second-level array has - PTHREAD_KEY_2NDLEVEL_SIZE - entries. This value shouldn't be too large. */ -#define PTHREAD_KEY_2NDLEVEL_SIZE 32 - -/* We need to address PTHREAD_KEYS_MAX key with PTHREAD_KEY_2NDLEVEL_SIZE - keys in each subarray. */ -#define PTHREAD_KEY_1STLEVEL_SIZE \ - ((PTHREAD_KEYS_MAX + PTHREAD_KEY_2NDLEVEL_SIZE - 1) \ - / PTHREAD_KEY_2NDLEVEL_SIZE) - -typedef void (*destr_function)(void *); - -struct pthread_key_struct { - int in_use; /* already allocated? */ - destr_function destr; /* destruction routine */ -}; - - -#define PTHREAD_START_ARGS_INITIALIZER { NULL, NULL, {{0, }}, 0, { 0 } } - -/* The type of thread descriptors */ - -typedef struct _pthread_descr_struct * pthread_descr; - -/* Callback interface for removing the thread from waiting on an - object if it is cancelled while waiting or about to wait. - This hold a pointer to the object, and a pointer to a function - which ``extricates'' the thread from its enqueued state. - The function takes two arguments: pointer to the wait object, - and a pointer to the thread. It returns 1 if an extrication - actually occured, and hence the thread must also be signalled. - It returns 0 if the thread had already been extricated. */ - -typedef struct _pthread_extricate_struct { - void *pu_object; - int (*pu_extricate_func)(void *, pthread_descr); -} pthread_extricate_if; - -/* Atomic counter made possible by compare_and_swap */ - -struct pthread_atomic { - long p_count; - int p_spinlock; -}; - -/* Context info for read write locks. The pthread_rwlock_info structure - is information about a lock that has been read-locked by the thread - in whose list this structure appears. The pthread_rwlock_context - is embedded in the thread context and contains a pointer to the - head of the list of lock info structures, as well as a count of - read locks that are untracked, because no info structure could be - allocated for them. */ - -struct _pthread_rwlock_t; - -typedef struct _pthread_rwlock_info { - struct _pthread_rwlock_info *pr_next; - struct _pthread_rwlock_t *pr_lock; - int pr_lock_count; -} pthread_readlock_info; - -struct _pthread_descr_struct { - pthread_descr p_nextlive, p_prevlive; - /* Double chaining of active threads */ - pthread_descr p_nextwaiting; /* Next element in the queue holding the thr */ - pthread_descr p_nextlock; /* can be on a queue and waiting on a lock */ - pthread_t p_tid; /* Thread identifier */ - int p_pid; /* PID of Unix process */ - int p_priority; /* Thread priority (== 0 if not realtime) */ - struct _pthread_fastlock * p_lock; /* Spinlock for synchronized accesses */ - int p_signal; /* last signal received */ - sigjmp_buf * p_signal_jmp; /* where to siglongjmp on a signal or NULL */ - sigjmp_buf * p_cancel_jmp; /* where to siglongjmp on a cancel or NULL */ - char p_terminated; /* true if terminated e.g. by pthread_exit */ - char p_detached; /* true if detached */ - char p_exited; /* true if the assoc. process terminated */ - void * p_retval; /* placeholder for return value */ - int p_retcode; /* placeholder for return code */ - pthread_descr p_joining; /* thread joining on that thread or NULL */ - struct _pthread_cleanup_buffer * p_cleanup; /* cleanup functions */ - char p_cancelstate; /* cancellation state */ - char p_canceltype; /* cancellation type (deferred/async) */ - char p_canceled; /* cancellation request pending */ - int * p_errnop; /* pointer to used errno variable */ - int p_errno; /* error returned by last system call */ - int * p_h_errnop; /* pointer to used h_errno variable */ - int p_h_errno; /* error returned by last netdb function */ - char * p_in_sighandler; /* stack address of sighandler, or NULL */ - char p_sigwaiting; /* true if a sigwait() is in progress */ - struct pthread_start_args p_start_args; /* arguments for thread creation */ - void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE]; /* thread-specific data */ - void * p_libc_specific[_LIBC_TSD_KEY_N]; /* thread-specific data for libc */ - int p_userstack; /* nonzero if the user provided the stack */ - void *p_guardaddr; /* address of guard area or NULL */ - size_t p_guardsize; /* size of guard area */ - pthread_descr p_self; /* Pointer to this structure */ - int p_nr; /* Index of descriptor in __pthread_handles */ - int p_report_events; /* Nonzero if events must be reported. */ - td_eventbuf_t p_eventbuf; /* Data for event. */ - struct pthread_atomic p_resume_count; /* number of times restart() was - called on thread */ - char p_woken_by_cancel; /* cancellation performed wakeup */ - char p_condvar_avail; /* flag if conditional variable became avail */ - char p_sem_avail; /* flag if semaphore became available */ - pthread_extricate_if *p_extricate; /* See above */ - pthread_readlock_info *p_readlock_list; /* List of readlock info structs */ - pthread_readlock_info *p_readlock_free; /* Free list of structs */ - int p_untracked_readlock_count; /* Readlocks not tracked by list */ - /* New elements must be added at the end. */ -#ifdef __UCLIBC_HAS_XLOCALE__ - __locale_t locale; /* thread-specific locale from uselocale() only! */ -#endif /* __UCLIBC_HAS_XLOCALE__ */ -} __attribute__ ((aligned(32))); /* We need to align the structure so that - doubles are aligned properly. This is 8 - bytes on MIPS and 16 bytes on MIPS64. - 32 bytes might give better cache - utilization. */ - -/* The type of thread handles. */ - -typedef struct pthread_handle_struct * pthread_handle; - -struct pthread_handle_struct { - struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */ - pthread_descr h_descr; /* Thread descriptor or NULL if invalid */ - char * h_bottom; /* Lowest address in the stack thread */ -}; - -/* The type of messages sent to the thread manager thread */ - -struct pthread_request { - pthread_descr req_thread; /* Thread doing the request */ - enum { /* Request kind */ - REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT, - REQ_POST, REQ_DEBUG, REQ_KICK - } req_kind; - union { /* Arguments for request */ - struct { /* For REQ_CREATE: */ - const pthread_attr_t * attr; /* thread attributes */ - void * (*fn)(void *); /* start function */ - void * arg; /* argument to start function */ - sigset_t mask; /* signal mask */ - } create; - struct { /* For REQ_FREE: */ - pthread_t thread_id; /* identifier of thread to free */ - } free; - struct { /* For REQ_PROCESS_EXIT: */ - int code; /* exit status */ - } exit; - void * post; /* For REQ_POST: the semaphore */ - } req_args; -}; - - -/* Signals used for suspend/restart and for cancellation notification. */ - -extern int __pthread_sig_restart; -extern int __pthread_sig_cancel; - -/* Signal used for interfacing with gdb */ - -extern int __pthread_sig_debug; - -/* Global array of thread handles, used for validating a thread id - and retrieving the corresponding thread descriptor. Also used for - mapping the available stack segments. */ - -extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX]; - -/* Descriptor of the initial thread */ - -extern struct _pthread_descr_struct __pthread_initial_thread; - -/* Descriptor of the manager thread */ - -extern struct _pthread_descr_struct __pthread_manager_thread; - -/* Descriptor of the main thread */ - -extern pthread_descr __pthread_main_thread; - -/* Limit between the stack of the initial thread (above) and the - stacks of other threads (below). Aligned on a STACK_SIZE boundary. - Initially 0, meaning that the current thread is (by definition) - the initial thread. */ - -/* For non-MMU systems also remember to stack top of the initial thread. - * This is adapted when other stacks are malloc'ed since we don't know - * the bounds a-priori. -StS */ - -extern char *__pthread_initial_thread_bos; -#ifndef __ARCH_HAS_MMU__ -extern char *__pthread_initial_thread_tos; -#define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) \ - if ((tos)>=__pthread_initial_thread_bos \ - && (bos)<__pthread_initial_thread_tos) \ - __pthread_initial_thread_bos = (tos)+1 -#else -#define NOMMU_INITIAL_THREAD_BOUNDS(tos,bos) /* empty */ -#endif /* __ARCH_HAS_MMU__ */ - - -/* Indicate whether at least one thread has a user-defined stack (if 1), - or all threads have stacks supplied by LinuxThreads (if 0). */ - -extern int __pthread_nonstandard_stacks; - -/* File descriptor for sending requests to the thread manager. - Initially -1, meaning that __pthread_initialize_manager must be called. */ - -extern int __pthread_manager_request; - -/* Other end of the pipe for sending requests to the thread manager. */ - -extern int __pthread_manager_reader; - -/* Limits of the thread manager stack. */ - -extern char *__pthread_manager_thread_bos; -extern char *__pthread_manager_thread_tos; - -/* Pending request for a process-wide exit */ - -extern int __pthread_exit_requested, __pthread_exit_code; - -/* Set to 1 by gdb if we're debugging */ - -extern volatile int __pthread_threads_debug; - -/* Globally enabled events. */ -extern volatile td_thr_events_t __pthread_threads_events; - -/* Pointer to descriptor of thread with last event. */ -extern volatile pthread_descr __pthread_last_event; - -/* Return the handle corresponding to a thread id */ - -static inline pthread_handle thread_handle(pthread_t id) -{ - return &__pthread_handles[id % PTHREAD_THREADS_MAX]; -} - -/* Validate a thread handle. Must have acquired h->h_spinlock before. */ - -static inline int invalid_handle(pthread_handle h, pthread_t id) -{ - return h->h_descr == NULL || h->h_descr->p_tid != id; -} - -/* Fill in defaults left unspecified by pt-machine.h. */ - -/* The page size we can get from the system. This should likely not be - changed by the machine file but, you never know. */ -extern size_t __pagesize; -#include -#ifndef PAGE_SIZE -#define PAGE_SIZE (sysconf (_SC_PAGESIZE)) -#endif - -/* The max size of the thread stack segments. If the default - THREAD_SELF implementation is used, this must be a power of two and - a multiple of PAGE_SIZE. */ -#ifndef STACK_SIZE -#ifdef __ARCH_HAS_MMU__ -#define STACK_SIZE (2 * 1024 * 1024) -#else -#define STACK_SIZE (4 * __pagesize) -#endif -#endif - -/* The initial size of the thread stack. Must be a multiple of PAGE_SIZE. */ -#ifndef INITIAL_STACK_SIZE -#define INITIAL_STACK_SIZE (4 * __pagesize) -#endif - -/* Size of the thread manager stack. The "- 32" avoids wasting space - with some malloc() implementations. */ -#ifndef THREAD_MANAGER_STACK_SIZE -#define THREAD_MANAGER_STACK_SIZE (2 * __pagesize - 32) -#endif - -/* The base of the "array" of thread stacks. The array will grow down from - here. Defaults to the calculated bottom of the initial application - stack. */ -#ifndef THREAD_STACK_START_ADDRESS -#define THREAD_STACK_START_ADDRESS __pthread_initial_thread_bos -#endif - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#ifndef CURRENT_STACK_FRAME -#define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) -#endif - -/* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the - architecture doesn't need a memory barrier instruction (e.g. Intel - x86). Still we need the compiler to respect the barrier and emit - all outstanding operations which modify memory. Some architectures - distinguish between full, read and write barriers. */ -#ifndef MEMORY_BARRIER -#define MEMORY_BARRIER() asm ("" : : : "memory") -#endif -#ifndef READ_MEMORY_BARRIER -#define READ_MEMORY_BARRIER() MEMORY_BARRIER() -#endif -#ifndef WRITE_MEMORY_BARRIER -#define WRITE_MEMORY_BARRIER() MEMORY_BARRIER() -#endif - -/* Recover thread descriptor for the current thread */ - -extern pthread_descr __pthread_find_self (void) __attribute__ ((const)); - -static inline pthread_descr thread_self (void) __attribute__ ((const)); -static inline pthread_descr thread_self (void) -{ -#ifdef THREAD_SELF - return THREAD_SELF; -#else - char *sp = CURRENT_STACK_FRAME; -#ifdef __ARCH_HAS_MMU__ - if (sp >= __pthread_initial_thread_bos) - return &__pthread_initial_thread; - else if (sp >= __pthread_manager_thread_bos - && sp < __pthread_manager_thread_tos) - return &__pthread_manager_thread; - else if (__pthread_nonstandard_stacks) - return __pthread_find_self(); - else - return (pthread_descr)(((unsigned long)sp | (STACK_SIZE-1))+1) - 1; -#else - /* For non-MMU we need to be more careful about the initial thread stack. - * We refine the initial thread stack bounds dynamically as we allocate - * the other stack frame such that it doesn't overlap with them. Then - * we can be sure to pick the right thread according to the current SP */ - - /* Since we allow other stack frames to be above or below, we need to - * treat this case special. When pthread_initialize() wasn't called yet, - * only the initial thread is there. */ - if (__pthread_initial_thread_bos == NULL) { - return &__pthread_initial_thread; - } - else if (sp >= __pthread_initial_thread_bos - && sp < __pthread_initial_thread_tos) { - return &__pthread_initial_thread; - } - else if (sp >= __pthread_manager_thread_bos - && sp < __pthread_manager_thread_tos) { - return &__pthread_manager_thread; - } - else { - return __pthread_find_self(); - } -#endif /* __ARCH_HAS_MMU__ */ -#endif -} - -/* Max number of times we must spin on a spinlock calling sched_yield(). - After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */ - -#ifndef MAX_SPIN_COUNT -#define MAX_SPIN_COUNT 50 -#endif - -/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock - after MAX_SPIN_COUNT iterations of sched_yield(). - With the 2.0 and 2.1 kernels, this MUST BE > 2ms. - (Otherwise the kernel does busy-waiting for realtime threads, - giving other threads no chance to run.) */ - -#ifndef SPIN_SLEEP_DURATION -#define SPIN_SLEEP_DURATION 2000001 -#endif - -/* Debugging */ - -#ifdef DEBUG -#include -#define ASSERT assert -#define MSG __pthread_message -#else -#define ASSERT(x) -#define MSG(msg,arg...) -#endif - -/* Internal global functions */ - -void __pthread_destroy_specifics(void); -void __pthread_perform_cleanup(void); -int __pthread_initialize_manager(void); -void __pthread_message(char * fmt, ...); -int __pthread_manager(void *reqfd); -int __pthread_manager_event(void *reqfd); -void __pthread_manager_sighandler(int sig); -void __pthread_reset_main_thread(void); -void __fresetlockfiles(void); -void __pthread_manager_adjust_prio(int thread_prio); -void __pthread_initialize_minimal (void); - -extern int __pthread_attr_setguardsize __P ((pthread_attr_t *__attr, - size_t __guardsize)); -extern int __pthread_attr_getguardsize __P ((__const pthread_attr_t *__attr, - size_t *__guardsize)); -extern int __pthread_attr_setstackaddr __P ((pthread_attr_t *__attr, - void *__stackaddr)); -extern int __pthread_attr_getstackaddr __P ((__const pthread_attr_t *__attr, - void **__stackaddr)); -extern int __pthread_attr_setstacksize __P ((pthread_attr_t *__attr, - size_t __stacksize)); -extern int __pthread_attr_getstacksize __P ((__const pthread_attr_t *__attr, - size_t *__stacksize)); -extern int __pthread_getconcurrency __P ((void)); -extern int __pthread_setconcurrency __P ((int __level)); -extern int __pthread_mutexattr_gettype __P ((__const pthread_mutexattr_t *__attr, - int *__kind)); -extern void __pthread_kill_other_threads_np __P ((void)); - -extern void __pthread_restart_old(pthread_descr th); -extern void __pthread_suspend_old(pthread_descr self); -extern int __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abs); - -extern void __pthread_restart_new(pthread_descr th); -extern void __pthread_suspend_new(pthread_descr self); -extern int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abs); - -extern void __pthread_wait_for_restart_signal(pthread_descr self); - -/* Global pointers to old or new suspend functions */ - -extern void (*__pthread_restart)(pthread_descr); -extern void (*__pthread_suspend)(pthread_descr); - -/* Prototypes for the function without cancelation support when the - normal version has it. */ -extern int __libc_close (int fd); -extern int __libc_nanosleep (const struct timespec *requested_time, - struct timespec *remaining); -extern ssize_t __libc_read (int fd, void *buf, size_t count); -extern pid_t __libc_waitpid (pid_t pid, int *stat_loc, int options); -extern ssize_t __libc_write (int fd, const void *buf, size_t count); - -/* Prototypes for some of the new semaphore functions. */ -extern int __new_sem_post (sem_t * sem); - -/* The functions called the signal events. */ -extern void __linuxthreads_create_event (void); -extern void __linuxthreads_death_event (void); -extern void __linuxthreads_reap_event (void); - -#endif /* internals.h */ diff --git a/libpthread/linuxthreads/join.c b/libpthread/linuxthreads/join.c deleted file mode 100644 index 5aeec6a20..000000000 --- a/libpthread/linuxthreads/join.c +++ /dev/null @@ -1,221 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Thread termination and joining */ - -#include -#define __USE_GNU -#include -#include -#include -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "restart.h" -#include "debug.h" /* PDEBUG, added by StS */ - -void pthread_exit(void * retval) -{ - pthread_descr self = thread_self(); - pthread_descr joining; - struct pthread_request request; - PDEBUG("self=%p, pid=%d\n", self, self->p_pid); - - /* Reset the cancellation flag to avoid looping if the cleanup handlers - contain cancellation points */ - THREAD_SETMEM(self, p_canceled, 0); - /* Call cleanup functions and destroy the thread-specific data */ - __pthread_perform_cleanup(); - __pthread_destroy_specifics(); - /* Store return value */ - __pthread_lock(THREAD_GETMEM(self, p_lock), self); - THREAD_SETMEM(self, p_retval, retval); - /* See whether we have to signal the death. */ - if (THREAD_GETMEM(self, p_report_events)) - { - /* See whether TD_DEATH is in any of the mask. */ - int idx = __td_eventword (TD_DEATH); - uint32_t mask = __td_eventmask (TD_DEATH); - - if ((mask & (__pthread_threads_events.event_bits[idx] - | THREAD_GETMEM_NC(self, - p_eventbuf.eventmask).event_bits[idx])) - != 0) - { - /* Yep, we have to signal the death. */ - THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH); - THREAD_SETMEM(self, p_eventbuf.eventdata, self); - __pthread_last_event = self; - - /* Now call the function to signal the event. */ - __linuxthreads_death_event(); - } - } - /* Say that we've terminated */ - THREAD_SETMEM(self, p_terminated, 1); - /* See if someone is joining on us */ - joining = THREAD_GETMEM(self, p_joining); - PDEBUG("joining = %p, pid=%d\n", joining, joining->p_pid); - __pthread_unlock(THREAD_GETMEM(self, p_lock)); - /* Restart joining thread if any */ - if (joining != NULL) restart(joining); - /* If this is the initial thread, block until all threads have terminated. - If another thread calls exit, we'll be terminated from our signal - handler. */ - if (self == __pthread_main_thread && __pthread_manager_request >= 0) { - request.req_thread = self; - request.req_kind = REQ_MAIN_THREAD_EXIT; - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *)&request, sizeof(request))); - suspend(self); - /* Main thread flushes stdio streams and runs atexit functions. - * It also calls a handler within LinuxThreads which sends a process exit - * request to the thread manager. */ - exit(0); - } - /* Exit the process (but don't flush stdio streams, and don't run - atexit functions). */ - _exit(0); -} - -/* Function called by pthread_cancel to remove the thread from - waiting on a condition variable queue. */ - -static int join_extricate_func(void *obj, pthread_descr th) -{ - volatile pthread_descr self = thread_self(); - pthread_handle handle = obj; - pthread_descr jo; - int did_remove = 0; - - __pthread_lock(&handle->h_lock, self); - jo = handle->h_descr; - did_remove = jo->p_joining != NULL; - jo->p_joining = NULL; - __pthread_unlock(&handle->h_lock); - - return did_remove; -} - -int pthread_join(pthread_t thread_id, void ** thread_return) -{ - volatile pthread_descr self = thread_self(); - struct pthread_request request; - pthread_handle handle = thread_handle(thread_id); - pthread_descr th; - pthread_extricate_if extr; - int already_canceled = 0; - PDEBUG("\n"); - - /* Set up extrication interface */ - extr.pu_object = handle; - extr.pu_extricate_func = join_extricate_func; - - __pthread_lock(&handle->h_lock, self); - if (invalid_handle(handle, thread_id)) { - __pthread_unlock(&handle->h_lock); - return ESRCH; - } - th = handle->h_descr; - if (th == self) { - __pthread_unlock(&handle->h_lock); - return EDEADLK; - } - /* If detached or already joined, error */ - if (th->p_detached || th->p_joining != NULL) { - __pthread_unlock(&handle->h_lock); - return EINVAL; - } - /* If not terminated yet, suspend ourselves. */ - if (! th->p_terminated) { - /* Register extrication interface */ - __pthread_set_own_extricate_if(self, &extr); - if (!(THREAD_GETMEM(self, p_canceled) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) - th->p_joining = self; - else - already_canceled = 1; - __pthread_unlock(&handle->h_lock); - - if (already_canceled) { - __pthread_set_own_extricate_if(self, 0); - pthread_exit(PTHREAD_CANCELED); - } - - PDEBUG("before suspend\n"); - suspend(self); - PDEBUG("after suspend\n"); - /* Deregister extrication interface */ - __pthread_set_own_extricate_if(self, 0); - - /* This is a cancellation point */ - if (THREAD_GETMEM(self, p_woken_by_cancel) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { - THREAD_SETMEM(self, p_woken_by_cancel, 0); - pthread_exit(PTHREAD_CANCELED); - } - __pthread_lock(&handle->h_lock, self); - } - /* Get return value */ - if (thread_return != NULL) *thread_return = th->p_retval; - __pthread_unlock(&handle->h_lock); - /* Send notification to thread manager */ - if (__pthread_manager_request >= 0) { - request.req_thread = self; - request.req_kind = REQ_FREE; - request.req_args.free.thread_id = thread_id; - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *) &request, sizeof(request))); - } - return 0; -} - -int pthread_detach(pthread_t thread_id) -{ - int terminated; - struct pthread_request request; - pthread_handle handle = thread_handle(thread_id); - pthread_descr th; - - __pthread_lock(&handle->h_lock, NULL); - if (invalid_handle(handle, thread_id)) { - __pthread_unlock(&handle->h_lock); - return ESRCH; - } - th = handle->h_descr; - /* If already detached, error */ - if (th->p_detached) { - __pthread_unlock(&handle->h_lock); - return EINVAL; - } - /* If already joining, don't do anything. */ - if (th->p_joining != NULL) { - __pthread_unlock(&handle->h_lock); - return 0; - } - /* Mark as detached */ - th->p_detached = 1; - terminated = th->p_terminated; - __pthread_unlock(&handle->h_lock); - /* If already terminated, notify thread manager to reclaim resources */ - if (terminated && __pthread_manager_request >= 0) { - request.req_thread = thread_self(); - request.req_kind = REQ_FREE; - request.req_args.free.thread_id = thread_id; - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *) &request, sizeof(request))); - } - return 0; -} diff --git a/libpthread/linuxthreads/linuxthreads.texi b/libpthread/linuxthreads/linuxthreads.texi deleted file mode 100644 index 795fb7097..000000000 --- a/libpthread/linuxthreads/linuxthreads.texi +++ /dev/null @@ -1,1627 +0,0 @@ -@node POSIX Threads -@c @node POSIX Threads, , Top, Top -@chapter POSIX Threads -@c %MENU% The standard threads library - -@c This chapter needs more work bigtime. -zw - -This chapter describes the pthreads (POSIX threads) library. This -library provides support functions for multithreaded programs: thread -primitives, synchronization objects, and so forth. It also implements -POSIX 1003.1b semaphores (not to be confused with System V semaphores). - -The threads operations (@samp{pthread_*}) do not use @var{errno}. -Instead they return an error code directly. The semaphore operations do -use @var{errno}. - -@menu -* Basic Thread Operations:: Creating, terminating, and waiting for threads. -* Thread Attributes:: Tuning thread scheduling. -* Cancellation:: Stopping a thread before it's done. -* Cleanup Handlers:: Deallocating resources when a thread is - canceled. -* Mutexes:: One way to synchronize threads. -* Condition Variables:: Another way. -* POSIX Semaphores:: And a third way. -* Thread-Specific Data:: Variables with different values in - different threads. -* Threads and Signal Handling:: Why you should avoid mixing the two, and - how to do it if you must. -* Threads and Fork:: Interactions between threads and the - @code{fork} function. -* Streams and Fork:: Interactions between stdio streams and - @code{fork}. -* Miscellaneous Thread Functions:: A grab bag of utility routines. -@end menu - -@node Basic Thread Operations -@section Basic Thread Operations - -These functions are the thread equivalents of @code{fork}, @code{exit}, -and @code{wait}. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_create (pthread_t * @var{thread}, pthread_attr_t * @var{attr}, void * (*@var{start_routine})(void *), void * @var{arg}) -@code{pthread_create} creates a new thread of control that executes -concurrently with the calling thread. The new thread calls the -function @var{start_routine}, passing it @var{arg} as first argument. The -new thread terminates either explicitly, by calling @code{pthread_exit}, -or implicitly, by returning from the @var{start_routine} function. The -latter case is equivalent to calling @code{pthread_exit} with the result -returned by @var{start_routine} as exit code. - -The @var{attr} argument specifies thread attributes to be applied to the -new thread. @xref{Thread Attributes}, for details. The @var{attr} -argument can also be @code{NULL}, in which case default attributes are -used: the created thread is joinable (not detached) and has an ordinary -(not realtime) scheduling policy. - -On success, the identifier of the newly created thread is stored in the -location pointed by the @var{thread} argument, and a 0 is returned. On -error, a non-zero error code is returned. - -This function may return the following errors: -@table @code -@item EAGAIN -Not enough system resources to create a process for the new thread, -or more than @code{PTHREAD_THREADS_MAX} threads are already active. -@end table -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun void pthread_exit (void *@var{retval}) -@code{pthread_exit} terminates the execution of the calling thread. All -cleanup handlers (@pxref{Cleanup Handlers}) that have been set for the -calling thread with @code{pthread_cleanup_push} are executed in reverse -order (the most recently pushed handler is executed first). Finalization -functions for thread-specific data are then called for all keys that -have non-@code{NULL} values associated with them in the calling thread -(@pxref{Thread-Specific Data}). Finally, execution of the calling -thread is stopped. - -The @var{retval} argument is the return value of the thread. It can be -retrieved from another thread using @code{pthread_join}. - -The @code{pthread_exit} function never returns. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_cancel (pthread_t @var{thread}) - -@code{pthread_cancel} sends a cancellation request to the thread denoted -by the @var{thread} argument. If there is no such thread, -@code{pthread_cancel} fails and returns @code{ESRCH}. Otherwise it -returns 0. @xref{Cancellation}, for details. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_join (pthread_t @var{th}, void **thread_@var{return}) -@code{pthread_join} suspends the execution of the calling thread until -the thread identified by @var{th} terminates, either by calling -@code{pthread_exit} or by being canceled. - -If @var{thread_return} is not @code{NULL}, the return value of @var{th} -is stored in the location pointed to by @var{thread_return}. The return -value of @var{th} is either the argument it gave to @code{pthread_exit}, -or @code{PTHREAD_CANCELED} if @var{th} was canceled. - -The joined thread @code{th} must be in the joinable state: it must not -have been detached using @code{pthread_detach} or the -@code{PTHREAD_CREATE_DETACHED} attribute to @code{pthread_create}. - -When a joinable thread terminates, its memory resources (thread -descriptor and stack) are not deallocated until another thread performs -@code{pthread_join} on it. Therefore, @code{pthread_join} must be called -once for each joinable thread created to avoid memory leaks. - -At most one thread can wait for the termination of a given -thread. Calling @code{pthread_join} on a thread @var{th} on which -another thread is already waiting for termination returns an error. - -@code{pthread_join} is a cancellation point. If a thread is canceled -while suspended in @code{pthread_join}, the thread execution resumes -immediately and the cancellation is executed without waiting for the -@var{th} thread to terminate. If cancellation occurs during -@code{pthread_join}, the @var{th} thread remains not joined. - -On success, the return value of @var{th} is stored in the location -pointed to by @var{thread_return}, and 0 is returned. On error, one of -the following values is returned: -@table @code -@item ESRCH -No thread could be found corresponding to that specified by @var{th}. -@item EINVAL -The @var{th} thread has been detached, or another thread is already -waiting on termination of @var{th}. -@item EDEADLK -The @var{th} argument refers to the calling thread. -@end table -@end deftypefun - -@node Thread Attributes -@section Thread Attributes - -@comment pthread.h -@comment POSIX - -Threads have a number of attributes that may be set at creation time. -This is done by filling a thread attribute object @var{attr} of type -@code{pthread_attr_t}, then passing it as second argument to -@code{pthread_create}. Passing @code{NULL} is equivalent to passing a -thread attribute object with all attributes set to their default values. - -Attribute objects are consulted only when creating a new thread. The -same attribute object can be used for creating several threads. -Modifying an attribute object after a call to @code{pthread_create} does -not change the attributes of the thread previously created. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_attr_init (pthread_attr_t *@var{attr}) -@code{pthread_attr_init} initializes the thread attribute object -@var{attr} and fills it with default values for the attributes. (The -default values are listed below for each attribute.) - -Each attribute @var{attrname} (see below for a list of all attributes) -can be individually set using the function -@code{pthread_attr_set@var{attrname}} and retrieved using the function -@code{pthread_attr_get@var{attrname}}. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_attr_destroy (pthread_attr_t *@var{attr}) -@code{pthread_attr_destroy} destroys the attribute object pointed to by -@var{attr} releasing any resources associated with it. @var{attr} is -left in an undefined state, and you must not use it again in a call to -any pthreads function until it has been reinitialized. -@end deftypefun - -@findex pthread_attr_setdetachstate -@findex pthread_attr_setguardsize -@findex pthread_attr_setinheritsched -@findex pthread_attr_setschedparam -@findex pthread_attr_setschedpolicy -@findex pthread_attr_setscope -@findex pthread_attr_setstack -@findex pthread_attr_setstackaddr -@findex pthread_attr_setstacksize -@comment pthread.h -@comment POSIX -@deftypefun int pthread_attr_setattr (pthread_attr_t *@var{obj}, int @var{value}) -Set attribute @var{attr} to @var{value} in the attribute object pointed -to by @var{obj}. See below for a list of possible attributes and the -values they can take. - -On success, these functions return 0. If @var{value} is not meaningful -for the @var{attr} being modified, they will return the error code -@code{EINVAL}. Some of the functions have other failure modes; see -below. -@end deftypefun - -@findex pthread_attr_getdetachstate -@findex pthread_attr_getguardsize -@findex pthread_attr_getinheritsched -@findex pthread_attr_getschedparam -@findex pthread_attr_getschedpolicy -@findex pthread_attr_getscope -@findex pthread_attr_getstack -@findex pthread_attr_getstackaddr -@findex pthread_attr_getstacksize -@comment pthread.h -@comment POSIX -@deftypefun int pthread_attr_getattr (const pthread_attr_t *@var{obj}, int *@var{value}) -Store the current setting of @var{attr} in @var{obj} into the variable -pointed to by @var{value}. - -These functions always return 0. -@end deftypefun - -The following thread attributes are supported: -@table @samp -@item detachstate -Choose whether the thread is created in the joinable state (value -@code{PTHREAD_CREATE_JOINABLE}) or in the detached state -(@code{PTHREAD_CREATE_DETACHED}). The default is -@code{PTHREAD_CREATE_JOINABLE}. - -In the joinable state, another thread can synchronize on the thread -termination and recover its termination code using @code{pthread_join}, -but some of the thread resources are kept allocated after the thread -terminates, and reclaimed only when another thread performs -@code{pthread_join} on that thread. - -In the detached state, the thread resources are immediately freed when -it terminates, but @code{pthread_join} cannot be used to synchronize on -the thread termination. - -A thread created in the joinable state can later be put in the detached -thread using @code{pthread_detach}. - -@item schedpolicy -Select the scheduling policy for the thread: one of @code{SCHED_OTHER} -(regular, non-realtime scheduling), @code{SCHED_RR} (realtime, -round-robin) or @code{SCHED_FIFO} (realtime, first-in first-out). -The default is @code{SCHED_OTHER}. -@c Not doc'd in our manual: FIXME. -@c See @code{sched_setpolicy} for more information on scheduling policies. - -The realtime scheduling policies @code{SCHED_RR} and @code{SCHED_FIFO} -are available only to processes with superuser privileges. -@code{pthread_attr_setschedparam} will fail and return @code{ENOTSUP} if -you try to set a realtime policy when you are unprivileged. - -The scheduling policy of a thread can be changed after creation with -@code{pthread_setschedparam}. - -@item schedparam -Change the scheduling parameter (the scheduling priority) -for the thread. The default is 0. - -This attribute is not significant if the scheduling policy is -@code{SCHED_OTHER}; it only matters for the realtime policies -@code{SCHED_RR} and @code{SCHED_FIFO}. - -The scheduling priority of a thread can be changed after creation with -@code{pthread_setschedparam}. - -@item inheritsched -Choose whether the scheduling policy and scheduling parameter for the -newly created thread are determined by the values of the -@var{schedpolicy} and @var{schedparam} attributes (value -@code{PTHREAD_EXPLICIT_SCHED}) or are inherited from the parent thread -(value @code{PTHREAD_INHERIT_SCHED}). The default is -@code{PTHREAD_EXPLICIT_SCHED}. - -@item scope -Choose the scheduling contention scope for the created thread. The -default is @code{PTHREAD_SCOPE_SYSTEM}, meaning that the threads contend -for CPU time with all processes running on the machine. In particular, -thread priorities are interpreted relative to the priorities of all -other processes on the machine. The other possibility, -@code{PTHREAD_SCOPE_PROCESS}, means that scheduling contention occurs -only between the threads of the running process: thread priorities are -interpreted relative to the priorities of the other threads of the -process, regardless of the priorities of other processes. - -@code{PTHREAD_SCOPE_PROCESS} is not supported in LinuxThreads. If you -try to set the scope to this value, @code{pthread_attr_setscope} will -fail and return @code{ENOTSUP}. - -@item stackaddr -Provide an address for an application managed stack. The size of the -stack must be at least @code{PTHREAD_STACK_MIN}. - -@item stacksize -Change the size of the stack created for the thread. The value defines -the minimum stack size, in bytes. - -If the value exceeds the system's maximum stack size, or is smaller -than @code{PTHREAD_STACK_MIN}, @code{pthread_attr_setstacksize} will -fail and return @code{EINVAL}. - -@item stack -Provide both the address and size of an application managed stack to -use for the new thread. The base of the memory area is @var{stackaddr} -with the size of the memory area, @var{stacksize}, measured in bytes. - -If the value of @var{stacksize} is less than @code{PTHREAD_STACK_MIN}, -or greater than the system's maximum stack size, or if the value of -@var{stackaddr} lacks the proper alignment, @code{pthread_attr_setstack} -will fail and return @code{EINVAL}. - -@item guardsize -Change the minimum size in bytes of the guard area for the thread's -stack. The default size is a single page. If this value is set, it -will be rounded up to the nearest page size. If the value is set to 0, -a guard area will not be created for this thread. The space allocated -for the guard area is used to catch stack overflow. Therefore, when -allocating large structures on the stack, a larger guard area may be -required to catch a stack overflow. - -If the caller is managing their own stacks (if the @code{stackaddr} -attribute has been set), then the @code{guardsize} attribute is ignored. - -If the value exceeds the @code{stacksize}, @code{pthread_atrr_setguardsize} -will fail and return @code{EINVAL}. -@end table - -@node Cancellation -@section Cancellation - -Cancellation is the mechanism by which a thread can terminate the -execution of another thread. More precisely, a thread can send a -cancellation request to another thread. Depending on its settings, the -target thread can then either ignore the request, honor it immediately, -or defer it till it reaches a cancellation point. When threads are -first created by @code{pthread_create}, they always defer cancellation -requests. - -When a thread eventually honors a cancellation request, it behaves as if -@code{pthread_exit(PTHREAD_CANCELED)} was called. All cleanup handlers -are executed in reverse order, finalization functions for -thread-specific data are called, and finally the thread stops executing. -If the canceled thread was joinable, the return value -@code{PTHREAD_CANCELED} is provided to whichever thread calls -@var{pthread_join} on it. See @code{pthread_exit} for more information. - -Cancellation points are the points where the thread checks for pending -cancellation requests and performs them. The POSIX threads functions -@code{pthread_join}, @code{pthread_cond_wait}, -@code{pthread_cond_timedwait}, @code{pthread_testcancel}, -@code{sem_wait}, and @code{sigwait} are cancellation points. In -addition, these system calls are cancellation points: - -@multitable @columnfractions .33 .33 .33 -@item @t{accept} @tab @t{open} @tab @t{sendmsg} -@item @t{close} @tab @t{pause} @tab @t{sendto} -@item @t{connect} @tab @t{read} @tab @t{system} -@item @t{fcntl} @tab @t{recv} @tab @t{tcdrain} -@item @t{fsync} @tab @t{recvfrom} @tab @t{wait} -@item @t{lseek} @tab @t{recvmsg} @tab @t{waitpid} -@item @t{msync} @tab @t{send} @tab @t{write} -@item @t{nanosleep} -@end multitable - -@noindent -All library functions that call these functions (such as -@code{printf}) are also cancellation points. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_setcancelstate (int @var{state}, int *@var{oldstate}) -@code{pthread_setcancelstate} changes the cancellation state for the -calling thread -- that is, whether cancellation requests are ignored or -not. The @var{state} argument is the new cancellation state: either -@code{PTHREAD_CANCEL_ENABLE} to enable cancellation, or -@code{PTHREAD_CANCEL_DISABLE} to disable cancellation (cancellation -requests are ignored). - -If @var{oldstate} is not @code{NULL}, the previous cancellation state is -stored in the location pointed to by @var{oldstate}, and can thus be -restored later by another call to @code{pthread_setcancelstate}. - -If the @var{state} argument is not @code{PTHREAD_CANCEL_ENABLE} or -@code{PTHREAD_CANCEL_DISABLE}, @code{pthread_setcancelstate} fails and -returns @code{EINVAL}. Otherwise it returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_setcanceltype (int @var{type}, int *@var{oldtype}) -@code{pthread_setcanceltype} changes the type of responses to -cancellation requests for the calling thread: asynchronous (immediate) -or deferred. The @var{type} argument is the new cancellation type: -either @code{PTHREAD_CANCEL_ASYNCHRONOUS} to cancel the calling thread -as soon as the cancellation request is received, or -@code{PTHREAD_CANCEL_DEFERRED} to keep the cancellation request pending -until the next cancellation point. If @var{oldtype} is not @code{NULL}, -the previous cancellation state is stored in the location pointed to by -@var{oldtype}, and can thus be restored later by another call to -@code{pthread_setcanceltype}. - -If the @var{type} argument is not @code{PTHREAD_CANCEL_DEFERRED} or -@code{PTHREAD_CANCEL_ASYNCHRONOUS}, @code{pthread_setcanceltype} fails -and returns @code{EINVAL}. Otherwise it returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun void pthread_testcancel (@var{void}) -@code{pthread_testcancel} does nothing except testing for pending -cancellation and executing it. Its purpose is to introduce explicit -checks for cancellation in long sequences of code that do not call -cancellation point functions otherwise. -@end deftypefun - -@node Cleanup Handlers -@section Cleanup Handlers - -Cleanup handlers are functions that get called when a thread terminates, -either by calling @code{pthread_exit} or because of -cancellation. Cleanup handlers are installed and removed following a -stack-like discipline. - -The purpose of cleanup handlers is to free the resources that a thread -may hold at the time it terminates. In particular, if a thread exits or -is canceled while it owns a locked mutex, the mutex will remain locked -forever and prevent other threads from executing normally. The best way -to avoid this is, just before locking the mutex, to install a cleanup -handler whose effect is to unlock the mutex. Cleanup handlers can be -used similarly to free blocks allocated with @code{malloc} or close file -descriptors on thread termination. - -Here is how to lock a mutex @var{mut} in such a way that it will be -unlocked if the thread is canceled while @var{mut} is locked: - -@smallexample -pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); -pthread_mutex_lock(&mut); -/* do some work */ -pthread_mutex_unlock(&mut); -pthread_cleanup_pop(0); -@end smallexample - -Equivalently, the last two lines can be replaced by - -@smallexample -pthread_cleanup_pop(1); -@end smallexample - -Notice that the code above is safe only in deferred cancellation mode -(see @code{pthread_setcanceltype}). In asynchronous cancellation mode, a -cancellation can occur between @code{pthread_cleanup_push} and -@code{pthread_mutex_lock}, or between @code{pthread_mutex_unlock} and -@code{pthread_cleanup_pop}, resulting in both cases in the thread trying -to unlock a mutex not locked by the current thread. This is the main -reason why asynchronous cancellation is difficult to use. - -If the code above must also work in asynchronous cancellation mode, -then it must switch to deferred mode for locking and unlocking the -mutex: - -@smallexample -pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); -pthread_cleanup_push(pthread_mutex_unlock, (void *) &mut); -pthread_mutex_lock(&mut); -/* do some work */ -pthread_cleanup_pop(1); -pthread_setcanceltype(oldtype, NULL); -@end smallexample - -The code above can be rewritten in a more compact and efficient way, -using the non-portable functions @code{pthread_cleanup_push_defer_np} -and @code{pthread_cleanup_pop_restore_np}: - -@smallexample -pthread_cleanup_push_defer_np(pthread_mutex_unlock, (void *) &mut); -pthread_mutex_lock(&mut); -/* do some work */ -pthread_cleanup_pop_restore_np(1); -@end smallexample - -@comment pthread.h -@comment POSIX -@deftypefun void pthread_cleanup_push (void (*@var{routine}) (void *), void *@var{arg}) - -@code{pthread_cleanup_push} installs the @var{routine} function with -argument @var{arg} as a cleanup handler. From this point on to the -matching @code{pthread_cleanup_pop}, the function @var{routine} will be -called with arguments @var{arg} when the thread terminates, either -through @code{pthread_exit} or by cancellation. If several cleanup -handlers are active at that point, they are called in LIFO order: the -most recently installed handler is called first. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun void pthread_cleanup_pop (int @var{execute}) -@code{pthread_cleanup_pop} removes the most recently installed cleanup -handler. If the @var{execute} argument is not 0, it also executes the -handler, by calling the @var{routine} function with arguments -@var{arg}. If the @var{execute} argument is 0, the handler is only -removed but not executed. -@end deftypefun - -Matching pairs of @code{pthread_cleanup_push} and -@code{pthread_cleanup_pop} must occur in the same function, at the same -level of block nesting. Actually, @code{pthread_cleanup_push} and -@code{pthread_cleanup_pop} are macros, and the expansion of -@code{pthread_cleanup_push} introduces an open brace @code{@{} with the -matching closing brace @code{@}} being introduced by the expansion of the -matching @code{pthread_cleanup_pop}. - -@comment pthread.h -@comment GNU -@deftypefun void pthread_cleanup_push_defer_np (void (*@var{routine}) (void *), void *@var{arg}) -@code{pthread_cleanup_push_defer_np} is a non-portable extension that -combines @code{pthread_cleanup_push} and @code{pthread_setcanceltype}. -It pushes a cleanup handler just as @code{pthread_cleanup_push} does, -but also saves the current cancellation type and sets it to deferred -cancellation. This ensures that the cleanup mechanism is effective even -if the thread was initially in asynchronous cancellation mode. -@end deftypefun - -@comment pthread.h -@comment GNU -@deftypefun void pthread_cleanup_pop_restore_np (int @var{execute}) -@code{pthread_cleanup_pop_restore_np} pops a cleanup handler introduced -by @code{pthread_cleanup_push_defer_np}, and restores the cancellation -type to its value at the time @code{pthread_cleanup_push_defer_np} was -called. -@end deftypefun - -@code{pthread_cleanup_push_defer_np} and -@code{pthread_cleanup_pop_restore_np} must occur in matching pairs, at -the same level of block nesting. - -The sequence - -@smallexample -pthread_cleanup_push_defer_np(routine, arg); -... -pthread_cleanup_pop_restore_np(execute); -@end smallexample - -@noindent -is functionally equivalent to (but more compact and efficient than) - -@smallexample -@{ - int oldtype; - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); - pthread_cleanup_push(routine, arg); - ... - pthread_cleanup_pop(execute); - pthread_setcanceltype(oldtype, NULL); -@} -@end smallexample - - -@node Mutexes -@section Mutexes - -A mutex is a MUTual EXclusion device, and is useful for protecting -shared data structures from concurrent modifications, and implementing -critical sections and monitors. - -A mutex has two possible states: unlocked (not owned by any thread), -and locked (owned by one thread). A mutex can never be owned by two -different threads simultaneously. A thread attempting to lock a mutex -that is already locked by another thread is suspended until the owning -thread unlocks the mutex first. - -None of the mutex functions is a cancellation point, not even -@code{pthread_mutex_lock}, in spite of the fact that it can suspend a -thread for arbitrary durations. This way, the status of mutexes at -cancellation points is predictable, allowing cancellation handlers to -unlock precisely those mutexes that need to be unlocked before the -thread stops executing. Consequently, threads using deferred -cancellation should never hold a mutex for extended periods of time. - -It is not safe to call mutex functions from a signal handler. In -particular, calling @code{pthread_mutex_lock} or -@code{pthread_mutex_unlock} from a signal handler may deadlock the -calling thread. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutex_init (pthread_mutex_t *@var{mutex}, const pthread_mutexattr_t *@var{mutexattr}) - -@code{pthread_mutex_init} initializes the mutex object pointed to by -@var{mutex} according to the mutex attributes specified in @var{mutexattr}. -If @var{mutexattr} is @code{NULL}, default attributes are used instead. - -The LinuxThreads implementation supports only one mutex attribute, -the @var{mutex type}, which is either ``fast'', ``recursive'', or -``error checking''. The type of a mutex determines whether -it can be locked again by a thread that already owns it. -The default type is ``fast''. - -Variables of type @code{pthread_mutex_t} can also be initialized -statically, using the constants @code{PTHREAD_MUTEX_INITIALIZER} (for -timed mutexes), @code{PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} (for -recursive mutexes), @code{PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP} -(for fast mutexes(, and @code{PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP} -(for error checking mutexes). - -@code{pthread_mutex_init} always returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutex_lock (pthread_mutex_t *mutex)) -@code{pthread_mutex_lock} locks the given mutex. If the mutex is -currently unlocked, it becomes locked and owned by the calling thread, -and @code{pthread_mutex_lock} returns immediately. If the mutex is -already locked by another thread, @code{pthread_mutex_lock} suspends the -calling thread until the mutex is unlocked. - -If the mutex is already locked by the calling thread, the behavior of -@code{pthread_mutex_lock} depends on the type of the mutex. If the mutex -is of the ``fast'' type, the calling thread is suspended. It will -remain suspended forever, because no other thread can unlock the mutex. -If the mutex is of the ``error checking'' type, @code{pthread_mutex_lock} -returns immediately with the error code @code{EDEADLK}. If the mutex is -of the ``recursive'' type, @code{pthread_mutex_lock} succeeds and -returns immediately, recording the number of times the calling thread -has locked the mutex. An equal number of @code{pthread_mutex_unlock} -operations must be performed before the mutex returns to the unlocked -state. -@c This doesn't discuss PTHREAD_MUTEX_TIMED_NP mutex attributes. FIXME -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutex_trylock (pthread_mutex_t *@var{mutex}) -@code{pthread_mutex_trylock} behaves identically to -@code{pthread_mutex_lock}, except that it does not block the calling -thread if the mutex is already locked by another thread (or by the -calling thread in the case of a ``fast'' mutex). Instead, -@code{pthread_mutex_trylock} returns immediately with the error code -@code{EBUSY}. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutex_timedlock (pthread_mutex_t *@var{mutex}, const struct timespec *@var{abstime}) -The @code{pthread_mutex_timedlock} is similar to the -@code{pthread_mutex_lock} function but instead of blocking for in -indefinite time if the mutex is locked by another thread, it returns -when the time specified in @var{abstime} is reached. - -This function can only be used on standard (``timed'') and ``error -checking'' mutexes. It behaves just like @code{pthread_mutex_lock} for -all other types. - -If the mutex is successfully locked, the function returns zero. If the -time specified in @var{abstime} is reached without the mutex being locked, -@code{ETIMEDOUT} is returned. - -This function was introduced in the POSIX.1d revision of the POSIX standard. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutex_unlock (pthread_mutex_t *@var{mutex}) -@code{pthread_mutex_unlock} unlocks the given mutex. The mutex is -assumed to be locked and owned by the calling thread on entrance to -@code{pthread_mutex_unlock}. If the mutex is of the ``fast'' type, -@code{pthread_mutex_unlock} always returns it to the unlocked state. If -it is of the ``recursive'' type, it decrements the locking count of the -mutex (number of @code{pthread_mutex_lock} operations performed on it by -the calling thread), and only when this count reaches zero is the mutex -actually unlocked. - -On ``error checking'' mutexes, @code{pthread_mutex_unlock} actually -checks at run-time that the mutex is locked on entrance, and that it was -locked by the same thread that is now calling -@code{pthread_mutex_unlock}. If these conditions are not met, -@code{pthread_mutex_unlock} returns @code{EPERM}, and the mutex remains -unchanged. ``Fast'' and ``recursive'' mutexes perform no such checks, -thus allowing a locked mutex to be unlocked by a thread other than its -owner. This is non-portable behavior and must not be relied upon. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutex_destroy (pthread_mutex_t *@var{mutex}) -@code{pthread_mutex_destroy} destroys a mutex object, freeing the -resources it might hold. The mutex must be unlocked on entrance. In the -LinuxThreads implementation, no resources are associated with mutex -objects, thus @code{pthread_mutex_destroy} actually does nothing except -checking that the mutex is unlocked. - -If the mutex is locked by some thread, @code{pthread_mutex_destroy} -returns @code{EBUSY}. Otherwise it returns 0. -@end deftypefun - -If any of the above functions (except @code{pthread_mutex_init}) -is applied to an uninitialized mutex, they will simply return -@code{EINVAL} and do nothing. - -A shared global variable @var{x} can be protected by a mutex as follows: - -@smallexample -int x; -pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; -@end smallexample - -All accesses and modifications to @var{x} should be bracketed by calls to -@code{pthread_mutex_lock} and @code{pthread_mutex_unlock} as follows: - -@smallexample -pthread_mutex_lock(&mut); -/* operate on x */ -pthread_mutex_unlock(&mut); -@end smallexample - -Mutex attributes can be specified at mutex creation time, by passing a -mutex attribute object as second argument to @code{pthread_mutex_init}. -Passing @code{NULL} is equivalent to passing a mutex attribute object -with all attributes set to their default values. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutexattr_init (pthread_mutexattr_t *@var{attr}) -@code{pthread_mutexattr_init} initializes the mutex attribute object -@var{attr} and fills it with default values for the attributes. - -This function always returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutexattr_destroy (pthread_mutexattr_t *@var{attr}) -@code{pthread_mutexattr_destroy} destroys a mutex attribute object, -which must not be reused until it is -reinitialized. @code{pthread_mutexattr_destroy} does nothing in the -LinuxThreads implementation. - -This function always returns 0. -@end deftypefun - -LinuxThreads supports only one mutex attribute: the mutex type, which is -either @code{PTHREAD_MUTEX_ADAPTIVE_NP} for ``fast'' mutexes, -@code{PTHREAD_MUTEX_RECURSIVE_NP} for ``recursive'' mutexes, -@code{PTHREAD_MUTEX_TIMED_NP} for ``timed'' mutexes, or -@code{PTHREAD_MUTEX_ERRORCHECK_NP} for ``error checking'' mutexes. As -the @code{NP} suffix indicates, this is a non-portable extension to the -POSIX standard and should not be employed in portable programs. - -The mutex type determines what happens if a thread attempts to lock a -mutex it already owns with @code{pthread_mutex_lock}. If the mutex is of -the ``fast'' type, @code{pthread_mutex_lock} simply suspends the calling -thread forever. If the mutex is of the ``error checking'' type, -@code{pthread_mutex_lock} returns immediately with the error code -@code{EDEADLK}. If the mutex is of the ``recursive'' type, the call to -@code{pthread_mutex_lock} returns immediately with a success return -code. The number of times the thread owning the mutex has locked it is -recorded in the mutex. The owning thread must call -@code{pthread_mutex_unlock} the same number of times before the mutex -returns to the unlocked state. - -The default mutex type is ``timed'', that is, @code{PTHREAD_MUTEX_TIMED_NP}. -@c This doesn't describe how a ``timed'' mutex behaves. FIXME - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutexattr_settype (pthread_mutexattr_t *@var{attr}, int @var{type}) -@code{pthread_mutexattr_settype} sets the mutex type attribute in -@var{attr} to the value specified by @var{type}. - -If @var{type} is not @code{PTHREAD_MUTEX_ADAPTIVE_NP}, -@code{PTHREAD_MUTEX_RECURSIVE_NP}, @code{PTHREAD_MUTEX_TIMED_NP}, or -@code{PTHREAD_MUTEX_ERRORCHECK_NP}, this function will return -@code{EINVAL} and leave @var{attr} unchanged. - -The standard Unix98 identifiers @code{PTHREAD_MUTEX_DEFAULT}, -@code{PTHREAD_MUTEX_NORMAL}, @code{PTHREAD_MUTEX_RECURSIVE}, -and @code{PTHREAD_MUTEX_ERRORCHECK} are also permitted. - -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_mutexattr_gettype (const pthread_mutexattr_t *@var{attr}, int *@var{type}) -@code{pthread_mutexattr_gettype} retrieves the current value of the -mutex type attribute in @var{attr} and stores it in the location pointed -to by @var{type}. - -This function always returns 0. -@end deftypefun - -@node Condition Variables -@section Condition Variables - -A condition (short for ``condition variable'') is a synchronization -device that allows threads to suspend execution until some predicate on -shared data is satisfied. The basic operations on conditions are: signal -the condition (when the predicate becomes true), and wait for the -condition, suspending the thread execution until another thread signals -the condition. - -A condition variable must always be associated with a mutex, to avoid -the race condition where a thread prepares to wait on a condition -variable and another thread signals the condition just before the first -thread actually waits on it. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_cond_init (pthread_cond_t *@var{cond}, pthread_condattr_t *cond_@var{attr}) - -@code{pthread_cond_init} initializes the condition variable @var{cond}, -using the condition attributes specified in @var{cond_attr}, or default -attributes if @var{cond_attr} is @code{NULL}. The LinuxThreads -implementation supports no attributes for conditions, hence the -@var{cond_attr} parameter is actually ignored. - -Variables of type @code{pthread_cond_t} can also be initialized -statically, using the constant @code{PTHREAD_COND_INITIALIZER}. - -This function always returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_cond_signal (pthread_cond_t *@var{cond}) -@code{pthread_cond_signal} restarts one of the threads that are waiting -on the condition variable @var{cond}. If no threads are waiting on -@var{cond}, nothing happens. If several threads are waiting on -@var{cond}, exactly one is restarted, but it is not specified which. - -This function always returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_cond_broadcast (pthread_cond_t *@var{cond}) -@code{pthread_cond_broadcast} restarts all the threads that are waiting -on the condition variable @var{cond}. Nothing happens if no threads are -waiting on @var{cond}. - -This function always returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_cond_wait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}) -@code{pthread_cond_wait} atomically unlocks the @var{mutex} (as per -@code{pthread_unlock_mutex}) and waits for the condition variable -@var{cond} to be signaled. The thread execution is suspended and does -not consume any CPU time until the condition variable is signaled. The -@var{mutex} must be locked by the calling thread on entrance to -@code{pthread_cond_wait}. Before returning to the calling thread, -@code{pthread_cond_wait} re-acquires @var{mutex} (as per -@code{pthread_lock_mutex}). - -Unlocking the mutex and suspending on the condition variable is done -atomically. Thus, if all threads always acquire the mutex before -signaling the condition, this guarantees that the condition cannot be -signaled (and thus ignored) between the time a thread locks the mutex -and the time it waits on the condition variable. - -This function always returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_cond_timedwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}, const struct timespec *@var{abstime}) -@code{pthread_cond_timedwait} atomically unlocks @var{mutex} and waits -on @var{cond}, as @code{pthread_cond_wait} does, but it also bounds the -duration of the wait. If @var{cond} has not been signaled before time -@var{abstime}, the mutex @var{mutex} is re-acquired and -@code{pthread_cond_timedwait} returns the error code @code{ETIMEDOUT}. -The wait can also be interrupted by a signal; in that case -@code{pthread_cond_timedwait} returns @code{EINTR}. - -The @var{abstime} parameter specifies an absolute time, with the same -origin as @code{time} and @code{gettimeofday}: an @var{abstime} of 0 -corresponds to 00:00:00 GMT, January 1, 1970. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_cond_destroy (pthread_cond_t *@var{cond}) -@code{pthread_cond_destroy} destroys the condition variable @var{cond}, -freeing the resources it might hold. If any threads are waiting on the -condition variable, @code{pthread_cond_destroy} leaves @var{cond} -untouched and returns @code{EBUSY}. Otherwise it returns 0, and -@var{cond} must not be used again until it is reinitialized. - -In the LinuxThreads implementation, no resources are associated with -condition variables, so @code{pthread_cond_destroy} actually does -nothing. -@end deftypefun - -@code{pthread_cond_wait} and @code{pthread_cond_timedwait} are -cancellation points. If a thread is canceled while suspended in one of -these functions, the thread immediately resumes execution, relocks the -mutex specified by @var{mutex}, and finally executes the cancellation. -Consequently, cleanup handlers are assured that @var{mutex} is locked -when they are called. - -It is not safe to call the condition variable functions from a signal -handler. In particular, calling @code{pthread_cond_signal} or -@code{pthread_cond_broadcast} from a signal handler may deadlock the -calling thread. - -Consider two shared variables @var{x} and @var{y}, protected by the -mutex @var{mut}, and a condition variable @var{cond} that is to be -signaled whenever @var{x} becomes greater than @var{y}. - -@smallexample -int x,y; -pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; -pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -@end smallexample - -Waiting until @var{x} is greater than @var{y} is performed as follows: - -@smallexample -pthread_mutex_lock(&mut); -while (x <= y) @{ - pthread_cond_wait(&cond, &mut); -@} -/* operate on x and y */ -pthread_mutex_unlock(&mut); -@end smallexample - -Modifications on @var{x} and @var{y} that may cause @var{x} to become greater than -@var{y} should signal the condition if needed: - -@smallexample -pthread_mutex_lock(&mut); -/* modify x and y */ -if (x > y) pthread_cond_broadcast(&cond); -pthread_mutex_unlock(&mut); -@end smallexample - -If it can be proved that at most one waiting thread needs to be waken -up (for instance, if there are only two threads communicating through -@var{x} and @var{y}), @code{pthread_cond_signal} can be used as a slightly more -efficient alternative to @code{pthread_cond_broadcast}. In doubt, use -@code{pthread_cond_broadcast}. - -To wait for @var{x} to becomes greater than @var{y} with a timeout of 5 -seconds, do: - -@smallexample -struct timeval now; -struct timespec timeout; -int retcode; - -pthread_mutex_lock(&mut); -gettimeofday(&now); -timeout.tv_sec = now.tv_sec + 5; -timeout.tv_nsec = now.tv_usec * 1000; -retcode = 0; -while (x <= y && retcode != ETIMEDOUT) @{ - retcode = pthread_cond_timedwait(&cond, &mut, &timeout); -@} -if (retcode == ETIMEDOUT) @{ - /* timeout occurred */ -@} else @{ - /* operate on x and y */ -@} -pthread_mutex_unlock(&mut); -@end smallexample - -Condition attributes can be specified at condition creation time, by -passing a condition attribute object as second argument to -@code{pthread_cond_init}. Passing @code{NULL} is equivalent to passing -a condition attribute object with all attributes set to their default -values. - -The LinuxThreads implementation supports no attributes for -conditions. The functions on condition attributes are included only for -compliance with the POSIX standard. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_condattr_init (pthread_condattr_t *@var{attr}) -@deftypefunx int pthread_condattr_destroy (pthread_condattr_t *@var{attr}) -@code{pthread_condattr_init} initializes the condition attribute object -@var{attr} and fills it with default values for the attributes. -@code{pthread_condattr_destroy} destroys the condition attribute object -@var{attr}. - -Both functions do nothing in the LinuxThreads implementation. - -@code{pthread_condattr_init} and @code{pthread_condattr_destroy} always -return 0. -@end deftypefun - -@node POSIX Semaphores -@section POSIX Semaphores - -@vindex SEM_VALUE_MAX -Semaphores are counters for resources shared between threads. The -basic operations on semaphores are: increment the counter atomically, -and wait until the counter is non-null and decrement it atomically. - -Semaphores have a maximum value past which they cannot be incremented. -The macro @code{SEM_VALUE_MAX} is defined to be this maximum value. In -the GNU C library, @code{SEM_VALUE_MAX} is equal to @code{INT_MAX} -(@pxref{Range of Type}), but it may be much smaller on other systems. - -The pthreads library implements POSIX 1003.1b semaphores. These should -not be confused with System V semaphores (@code{ipc}, @code{semctl} and -@code{semop}). -@c !!! SysV IPC is not doc'd at all in our manual - -All the semaphore functions and macros are defined in @file{semaphore.h}. - -@comment semaphore.h -@comment POSIX -@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}) -@code{sem_init} initializes the semaphore object pointed to by -@var{sem}. The count associated with the semaphore is set initially to -@var{value}. The @var{pshared} argument indicates whether the semaphore -is local to the current process (@var{pshared} is zero) or is to be -shared between several processes (@var{pshared} is not zero). - -On success @code{sem_init} returns 0. On failure it returns -1 and sets -@var{errno} to one of the following values: - -@table @code -@item EINVAL -@var{value} exceeds the maximal counter value @code{SEM_VALUE_MAX} - -@item ENOSYS -@var{pshared} is not zero. LinuxThreads currently does not support -process-shared semaphores. (This will eventually change.) -@end table -@end deftypefun - -@comment semaphore.h -@comment POSIX -@deftypefun int sem_destroy (sem_t * @var{sem}) -@code{sem_destroy} destroys a semaphore object, freeing the resources it -might hold. If any threads are waiting on the semaphore when -@code{sem_destroy} is called, it fails and sets @var{errno} to -@code{EBUSY}. - -In the LinuxThreads implementation, no resources are associated with -semaphore objects, thus @code{sem_destroy} actually does nothing except -checking that no thread is waiting on the semaphore. This will change -when process-shared semaphores are implemented. -@end deftypefun - -@comment semaphore.h -@comment POSIX -@deftypefun int sem_wait (sem_t * @var{sem}) -@code{sem_wait} suspends the calling thread until the semaphore pointed -to by @var{sem} has non-zero count. It then atomically decreases the -semaphore count. - -@code{sem_wait} is a cancellation point. It always returns 0. -@end deftypefun - -@comment semaphore.h -@comment POSIX -@deftypefun int sem_trywait (sem_t * @var{sem}) -@code{sem_trywait} is a non-blocking variant of @code{sem_wait}. If the -semaphore pointed to by @var{sem} has non-zero count, the count is -atomically decreased and @code{sem_trywait} immediately returns 0. If -the semaphore count is zero, @code{sem_trywait} immediately returns -1 -and sets errno to @code{EAGAIN}. -@end deftypefun - -@comment semaphore.h -@comment POSIX -@deftypefun int sem_post (sem_t * @var{sem}) -@code{sem_post} atomically increases the count of the semaphore pointed to -by @var{sem}. This function never blocks. - -@c !!! This para appears not to agree with the code. -On processors supporting atomic compare-and-swap (Intel 486, Pentium and -later, Alpha, PowerPC, MIPS II, Motorola 68k, Ultrasparc), the -@code{sem_post} function is can safely be called from signal handlers. -This is the only thread synchronization function provided by POSIX -threads that is async-signal safe. On the Intel 386 and earlier Sparc -chips, the current LinuxThreads implementation of @code{sem_post} is not -async-signal safe, because the hardware does not support the required -atomic operations. - -@code{sem_post} always succeeds and returns 0, unless the semaphore -count would exceed @code{SEM_VALUE_MAX} after being incremented. In -that case @code{sem_post} returns -1 and sets @var{errno} to -@code{EINVAL}. The semaphore count is left unchanged. -@end deftypefun - -@comment semaphore.h -@comment POSIX -@deftypefun int sem_getvalue (sem_t * @var{sem}, int * @var{sval}) -@code{sem_getvalue} stores in the location pointed to by @var{sval} the -current count of the semaphore @var{sem}. It always returns 0. -@end deftypefun - -@node Thread-Specific Data -@section Thread-Specific Data - -Programs often need global or static variables that have different -values in different threads. Since threads share one memory space, this -cannot be achieved with regular variables. Thread-specific data is the -POSIX threads answer to this need. - -Each thread possesses a private memory block, the thread-specific data -area, or TSD area for short. This area is indexed by TSD keys. The TSD -area associates values of type @code{void *} to TSD keys. TSD keys are -common to all threads, but the value associated with a given TSD key can -be different in each thread. - -For concreteness, the TSD areas can be viewed as arrays of @code{void *} -pointers, TSD keys as integer indices into these arrays, and the value -of a TSD key as the value of the corresponding array element in the -calling thread. - -When a thread is created, its TSD area initially associates @code{NULL} -with all keys. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_key_create (pthread_key_t *@var{key}, void (*destr_function) (void *)) -@code{pthread_key_create} allocates a new TSD key. The key is stored in -the location pointed to by @var{key}. There is a limit of -@code{PTHREAD_KEYS_MAX} on the number of keys allocated at a given -time. The value initially associated with the returned key is -@code{NULL} in all currently executing threads. - -The @var{destr_function} argument, if not @code{NULL}, specifies a -destructor function associated with the key. When a thread terminates -via @code{pthread_exit} or by cancellation, @var{destr_function} is -called on the value associated with the key in that thread. The -@var{destr_function} is not called if a key is deleted with -@code{pthread_key_delete} or a value is changed with -@code{pthread_setspecific}. The order in which destructor functions are -called at thread termination time is unspecified. - -Before the destructor function is called, the @code{NULL} value is -associated with the key in the current thread. A destructor function -might, however, re-associate non-@code{NULL} values to that key or some -other key. To deal with this, if after all the destructors have been -called for all non-@code{NULL} values, there are still some -non-@code{NULL} values with associated destructors, then the process is -repeated. The LinuxThreads implementation stops the process after -@code{PTHREAD_DESTRUCTOR_ITERATIONS} iterations, even if some -non-@code{NULL} values with associated descriptors remain. Other -implementations may loop indefinitely. - -@code{pthread_key_create} returns 0 unless @code{PTHREAD_KEYS_MAX} keys -have already been allocated, in which case it fails and returns -@code{EAGAIN}. -@end deftypefun - - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_key_delete (pthread_key_t @var{key}) -@code{pthread_key_delete} deallocates a TSD key. It does not check -whether non-@code{NULL} values are associated with that key in the -currently executing threads, nor call the destructor function associated -with the key. - -If there is no such key @var{key}, it returns @code{EINVAL}. Otherwise -it returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_setspecific (pthread_key_t @var{key}, const void *@var{pointer}) -@code{pthread_setspecific} changes the value associated with @var{key} -in the calling thread, storing the given @var{pointer} instead. - -If there is no such key @var{key}, it returns @code{EINVAL}. Otherwise -it returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun {void *} pthread_getspecific (pthread_key_t @var{key}) -@code{pthread_getspecific} returns the value currently associated with -@var{key} in the calling thread. - -If there is no such key @var{key}, it returns @code{NULL}. -@end deftypefun - -The following code fragment allocates a thread-specific array of 100 -characters, with automatic reclaimation at thread exit: - -@smallexample -/* Key for the thread-specific buffer */ -static pthread_key_t buffer_key; - -/* Once-only initialisation of the key */ -static pthread_once_t buffer_key_once = PTHREAD_ONCE_INIT; - -/* Allocate the thread-specific buffer */ -void buffer_alloc(void) -@{ - pthread_once(&buffer_key_once, buffer_key_alloc); - pthread_setspecific(buffer_key, malloc(100)); -@} - -/* Return the thread-specific buffer */ -char * get_buffer(void) -@{ - return (char *) pthread_getspecific(buffer_key); -@} - -/* Allocate the key */ -static void buffer_key_alloc() -@{ - pthread_key_create(&buffer_key, buffer_destroy); -@} - -/* Free the thread-specific buffer */ -static void buffer_destroy(void * buf) -@{ - free(buf); -@} -@end smallexample - -@node Threads and Signal Handling -@section Threads and Signal Handling - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_sigmask (int @var{how}, const sigset_t *@var{newmask}, sigset_t *@var{oldmask}) -@code{pthread_sigmask} changes the signal mask for the calling thread as -described by the @var{how} and @var{newmask} arguments. If @var{oldmask} -is not @code{NULL}, the previous signal mask is stored in the location -pointed to by @var{oldmask}. - -The meaning of the @var{how} and @var{newmask} arguments is the same as -for @code{sigprocmask}. If @var{how} is @code{SIG_SETMASK}, the signal -mask is set to @var{newmask}. If @var{how} is @code{SIG_BLOCK}, the -signals specified to @var{newmask} are added to the current signal mask. -If @var{how} is @code{SIG_UNBLOCK}, the signals specified to -@var{newmask} are removed from the current signal mask. - -Recall that signal masks are set on a per-thread basis, but signal -actions and signal handlers, as set with @code{sigaction}, are shared -between all threads. - -The @code{pthread_sigmask} function returns 0 on success, and one of the -following error codes on error: -@table @code -@item EINVAL -@var{how} is not one of @code{SIG_SETMASK}, @code{SIG_BLOCK}, or @code{SIG_UNBLOCK} - -@item EFAULT -@var{newmask} or @var{oldmask} point to invalid addresses -@end table -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_kill (pthread_t @var{thread}, int @var{signo}) -@code{pthread_kill} sends signal number @var{signo} to the thread -@var{thread}. The signal is delivered and handled as described in -@ref{Signal Handling}. - -@code{pthread_kill} returns 0 on success, one of the following error codes -on error: -@table @code -@item EINVAL -@var{signo} is not a valid signal number - -@item ESRCH -The thread @var{thread} does not exist (e.g. it has already terminated) -@end table -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int sigwait (const sigset_t *@var{set}, int *@var{sig}) -@code{sigwait} suspends the calling thread until one of the signals in -@var{set} is delivered to the calling thread. It then stores the number -of the signal received in the location pointed to by @var{sig} and -returns. The signals in @var{set} must be blocked and not ignored on -entrance to @code{sigwait}. If the delivered signal has a signal handler -function attached, that function is @emph{not} called. - -@code{sigwait} is a cancellation point. It always returns 0. -@end deftypefun - -For @code{sigwait} to work reliably, the signals being waited for must be -blocked in all threads, not only in the calling thread, since -otherwise the POSIX semantics for signal delivery do not guarantee -that it's the thread doing the @code{sigwait} that will receive the signal. -The best way to achieve this is block those signals before any threads -are created, and never unblock them in the program other than by -calling @code{sigwait}. - -Signal handling in LinuxThreads departs significantly from the POSIX -standard. According to the standard, ``asynchronous'' (external) signals -are addressed to the whole process (the collection of all threads), -which then delivers them to one particular thread. The thread that -actually receives the signal is any thread that does not currently block -the signal. - -In LinuxThreads, each thread is actually a kernel process with its own -PID, so external signals are always directed to one particular thread. -If, for instance, another thread is blocked in @code{sigwait} on that -signal, it will not be restarted. - -The LinuxThreads implementation of @code{sigwait} installs dummy signal -handlers for the signals in @var{set} for the duration of the -wait. Since signal handlers are shared between all threads, other -threads must not attach their own signal handlers to these signals, or -alternatively they should all block these signals (which is recommended -anyway). - -@node Threads and Fork -@section Threads and Fork - -It's not intuitively obvious what should happen when a multi-threaded POSIX -process calls @code{fork}. Not only are the semantics tricky, but you may -need to write code that does the right thing at fork time even if that code -doesn't use the @code{fork} function. Moreover, you need to be aware of -interaction between @code{fork} and some library features like -@code{pthread_once} and stdio streams. - -When @code{fork} is called by one of the threads of a process, it creates a new -process which is copy of the calling process. Effectively, in addition to -copying certain system objects, the function takes a snapshot of the memory -areas of the parent process, and creates identical areas in the child. -To make matters more complicated, with threads it's possible for two or more -threads to concurrently call fork to create two or more child processes. - -The child process has a copy of the address space of the parent, but it does -not inherit any of its threads. Execution of the child process is carried out -by a new thread which returns from @code{fork} function with a return value of -zero; it is the only thread in the child process. Because threads are not -inherited across fork, issues arise. At the time of the call to @code{fork}, -threads in the parent process other than the one calling @code{fork} may have -been executing critical regions of code. As a result, the child process may -get a copy of objects that are not in a well-defined state. This potential -problem affects all components of the program. - -Any program component which will continue being used in a child process must -correctly handle its state during @code{fork}. For this purpose, the POSIX -interface provides the special function @code{pthread_atfork} for installing -pointers to handler functions which are called from within @code{fork}. - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_atfork (void (*@var{prepare})(void), void (*@var{parent})(void), void (*@var{child})(void)) - -@code{pthread_atfork} registers handler functions to be called just -before and just after a new process is created with @code{fork}. The -@var{prepare} handler will be called from the parent process, just -before the new process is created. The @var{parent} handler will be -called from the parent process, just before @code{fork} returns. The -@var{child} handler will be called from the child process, just before -@code{fork} returns. - -@code{pthread_atfork} returns 0 on success and a non-zero error code on -error. - -One or more of the three handlers @var{prepare}, @var{parent} and -@var{child} can be given as @code{NULL}, meaning that no handler needs -to be called at the corresponding point. - -@code{pthread_atfork} can be called several times to install several -sets of handlers. At @code{fork} time, the @var{prepare} handlers are -called in LIFO order (last added with @code{pthread_atfork}, first -called before @code{fork}), while the @var{parent} and @var{child} -handlers are called in FIFO order (first added, first called). - -If there is insufficient memory available to register the handlers, -@code{pthread_atfork} fails and returns @code{ENOMEM}. Otherwise it -returns 0. - -The functions @code{fork} and @code{pthread_atfork} must not be regarded as -reentrant from the context of the handlers. That is to say, if a -@code{pthread_atfork} handler invoked from within @code{fork} calls -@code{pthread_atfork} or @code{fork}, the behavior is undefined. - -Registering a triplet of handlers is an atomic operation with respect to fork. -If new handlers are registered at about the same time as a fork occurs, either -all three handlers will be called, or none of them will be called. - -The handlers are inherited by the child process, and there is no -way to remove them, short of using @code{exec} to load a new -pocess image. - -@end deftypefun - -To understand the purpose of @code{pthread_atfork}, recall that -@code{fork} duplicates the whole memory space, including mutexes in -their current locking state, but only the calling thread: other threads -are not running in the child process. The mutexes are not usable after -the @code{fork} and must be initialized with @code{pthread_mutex_init} -in the child process. This is a limitation of the current -implementation and might or might not be present in future versions. - -To avoid this, install handlers with @code{pthread_atfork} as follows: have the -@var{prepare} handler lock the mutexes (in locking order), and the -@var{parent} handler unlock the mutexes. The @var{child} handler should reset -the mutexes using @code{pthread_mutex_init}, as well as any other -synchronization objects such as condition variables. - -Locking the global mutexes before the fork ensures that all other threads are -locked out of the critical regions of code protected by those mutexes. Thus -when @code{fork} takes a snapshot of the parent's address space, that snapshot -will copy valid, stable data. Resetting the synchronization objects in the -child process will ensure they are properly cleansed of any artifacts from the -threading subsystem of the parent process. For example, a mutex may inherit -a wait queue of threads waiting for the lock; this wait queue makes no sense -in the child process. Initializing the mutex takes care of this. - -@node Streams and Fork -@section Streams and Fork - -The GNU standard I/O library has an internal mutex which guards the internal -linked list of all standard C FILE objects. This mutex is properly taken care -of during @code{fork} so that the child receives an intact copy of the list. -This allows the @code{fopen} function, and related stream-creating functions, -to work correctly in the child process, since these functions need to insert -into the list. - -However, the individual stream locks are not completely taken care of. Thus -unless the multithreaded application takes special precautions in its use of -@code{fork}, the child process might not be able to safely use the streams that -it inherited from the parent. In general, for any given open stream in the -parent that is to be used by the child process, the application must ensure -that that stream is not in use by another thread when @code{fork} is called. -Otherwise an inconsistent copy of the stream object be produced. An easy way to -ensure this is to use @code{flockfile} to lock the stream prior to calling -@code{fork} and then unlock it with @code{funlockfile} inside the parent -process, provided that the parent's threads properly honor these locks. -Nothing special needs to be done in the child process, since the library -internally resets all stream locks. - -Note that the stream locks are not shared between the parent and child. -For example, even if you ensure that, say, the stream @code{stdout} is properly -treated and can be safely used in the child, the stream locks do not provide -an exclusion mechanism between the parent and child. If both processes write -to @code{stdout}, strangely interleaved output may result regardless of -the explicit use of @code{flockfile} or implicit locks. - -Also note that these provisions are a GNU extension; other systems might not -provide any way for streams to be used in the child of a multithreaded process. -POSIX requires that such a child process confines itself to calling only -asynchronous safe functions, which excludes much of the library, including -standard I/O. - -@node Miscellaneous Thread Functions -@section Miscellaneous Thread Functions - -@comment pthread.h -@comment POSIX -@deftypefun {pthread_t} pthread_self (@var{void}) -@code{pthread_self} returns the thread identifier for the calling thread. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_equal (pthread_t thread1, pthread_t thread2) -@code{pthread_equal} determines if two thread identifiers refer to the same -thread. - -A non-zero value is returned if @var{thread1} and @var{thread2} refer to -the same thread. Otherwise, 0 is returned. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_detach (pthread_t @var{th}) -@code{pthread_detach} puts the thread @var{th} in the detached -state. This guarantees that the memory resources consumed by @var{th} -will be freed immediately when @var{th} terminates. However, this -prevents other threads from synchronizing on the termination of @var{th} -using @code{pthread_join}. - -A thread can be created initially in the detached state, using the -@code{detachstate} attribute to @code{pthread_create}. In contrast, -@code{pthread_detach} applies to threads created in the joinable state, -and which need to be put in the detached state later. - -After @code{pthread_detach} completes, subsequent attempts to perform -@code{pthread_join} on @var{th} will fail. If another thread is already -joining the thread @var{th} at the time @code{pthread_detach} is called, -@code{pthread_detach} does nothing and leaves @var{th} in the joinable -state. - -On success, 0 is returned. On error, one of the following codes is -returned: -@table @code -@item ESRCH -No thread could be found corresponding to that specified by @var{th} -@item EINVAL -The thread @var{th} is already in the detached state -@end table -@end deftypefun - -@comment pthread.h -@comment GNU -@deftypefun void pthread_kill_other_threads_np (@var{void}) -@code{pthread_kill_other_threads_np} is a non-portable LinuxThreads extension. -It causes all threads in the program to terminate immediately, except -the calling thread which proceeds normally. It is intended to be -called just before a thread calls one of the @code{exec} functions, -e.g. @code{execve}. - -Termination of the other threads is not performed through -@code{pthread_cancel} and completely bypasses the cancellation -mechanism. Hence, the current settings for cancellation state and -cancellation type are ignored, and the cleanup handlers are not -executed in the terminated threads. - -According to POSIX 1003.1c, a successful @code{exec*} in one of the -threads should automatically terminate all other threads in the program. -This behavior is not yet implemented in LinuxThreads. Calling -@code{pthread_kill_other_threads_np} before @code{exec*} achieves much -of the same behavior, except that if @code{exec*} ultimately fails, then -all other threads are already killed. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_once (pthread_once_t *once_@var{control}, void (*@var{init_routine}) (void)) - -The purpose of @code{pthread_once} is to ensure that a piece of -initialization code is executed at most once. The @var{once_control} -argument points to a static or extern variable statically initialized -to @code{PTHREAD_ONCE_INIT}. - -The first time @code{pthread_once} is called with a given -@var{once_control} argument, it calls @var{init_routine} with no -argument and changes the value of the @var{once_control} variable to -record that initialization has been performed. Subsequent calls to -@code{pthread_once} with the same @code{once_control} argument do -nothing. - -If a thread is cancelled while executing @var{init_routine} -the state of the @var{once_control} variable is reset so that -a future call to @code{pthread_once} will call the routine again. - -If the process forks while one or more threads are executing -@code{pthread_once} initialization routines, the states of their respective -@var{once_control} variables will appear to be reset in the child process so -that if the child calls @code{pthread_once}, the routines will be executed. - -@code{pthread_once} always returns 0. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_setschedparam (pthread_t target_@var{thread}, int @var{policy}, const struct sched_param *@var{param}) - -@code{pthread_setschedparam} sets the scheduling parameters for the -thread @var{target_thread} as indicated by @var{policy} and -@var{param}. @var{policy} can be either @code{SCHED_OTHER} (regular, -non-realtime scheduling), @code{SCHED_RR} (realtime, round-robin) or -@code{SCHED_FIFO} (realtime, first-in first-out). @var{param} specifies -the scheduling priority for the two realtime policies. See -@code{sched_setpolicy} for more information on scheduling policies. - -The realtime scheduling policies @code{SCHED_RR} and @code{SCHED_FIFO} -are available only to processes with superuser privileges. - -On success, @code{pthread_setschedparam} returns 0. On error it returns -one of the following codes: -@table @code -@item EINVAL -@var{policy} is not one of @code{SCHED_OTHER}, @code{SCHED_RR}, -@code{SCHED_FIFO}, or the priority value specified by @var{param} is not -valid for the specified policy - -@item EPERM -Realtime scheduling was requested but the calling process does not have -sufficient privileges. - -@item ESRCH -The @var{target_thread} is invalid or has already terminated - -@item EFAULT -@var{param} points outside the process memory space -@end table -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_getschedparam (pthread_t target_@var{thread}, int *@var{policy}, struct sched_param *@var{param}) - -@code{pthread_getschedparam} retrieves the scheduling policy and -scheduling parameters for the thread @var{target_thread} and stores them -in the locations pointed to by @var{policy} and @var{param}, -respectively. - -@code{pthread_getschedparam} returns 0 on success, or one of the -following error codes on failure: -@table @code -@item ESRCH -The @var{target_thread} is invalid or has already terminated. - -@item EFAULT -@var{policy} or @var{param} point outside the process memory space. - -@end table -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_setconcurrency (int @var{level}) -@code{pthread_setconcurrency} is unused in LinuxThreads due to the lack -of a mapping of user threads to kernel threads. It exists for source -compatibility. It does store the value @var{level} so that it can be -returned by a subsequent call to @code{pthread_getconcurrency}. It takes -no other action however. -@end deftypefun - -@comment pthread.h -@comment POSIX -@deftypefun int pthread_getconcurrency () -@code{pthread_getconcurrency} is unused in LinuxThreads due to the lack -of a mapping of user threads to kernel threads. It exists for source -compatibility. However, it will return the value that was set by the -last call to @code{pthread_setconcurrency}. -@end deftypefun diff --git a/libpthread/linuxthreads/locale.c b/libpthread/linuxthreads/locale.c deleted file mode 100644 index c3ebbc285..000000000 --- a/libpthread/linuxthreads/locale.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (C) 2003 Manuel Novoa III - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define _GNU_SOURCE -#include -#include "pthread.h" -#include "internals.h" -#include -#include -#include - -extern struct _pthread_descr_struct __pthread_initial_thread; - -__locale_t __curlocale(void) -{ - pthread_descr self = thread_self(); - -#ifdef NDEBUG - return THREAD_GETMEM (self, locale); -#else - { - __locale_t r = THREAD_GETMEM (self, locale); - - assert(r); - - return r; - } -#endif -} - -__locale_t __curlocale_set(__locale_t newloc) -{ - __locale_t oldloc; - pthread_descr self = thread_self(); - - oldloc = THREAD_GETMEM (self, locale); - - assert(newloc != LC_GLOBAL_LOCALE); - assert(oldloc); - - THREAD_SETMEM (self, locale, newloc); - - return oldloc; -} diff --git a/libpthread/linuxthreads/lockfile.c b/libpthread/linuxthreads/lockfile.c deleted file mode 100644 index b0f41c98a..000000000 --- a/libpthread/linuxthreads/lockfile.c +++ /dev/null @@ -1,39 +0,0 @@ -/* lockfile - Handle locking and unlocking of stream. - Copyright (C) 1996, 1998, 2000 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include -#include - -/* Note: glibc puts flockfile, funlockfile, and ftrylockfile in both - * libc and libpthread. In uClibc, they are now in libc only. */ - -void -__fresetlockfiles (void) -{ - FILE *fp; - pthread_mutexattr_t attr; - - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); - - for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) - pthread_mutex_init(&fp->__lock, &attr); - - pthread_mutexattr_destroy(&attr); -} diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c deleted file mode 100644 index 204344aef..000000000 --- a/libpthread/linuxthreads/manager.c +++ /dev/null @@ -1,905 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* The "thread manager" thread: manages creation and termination of threads */ - -/* mods for uClibc: getpwd and getpagesize are the syscalls */ -#define __getpid getpid -#define __getpagesize getpagesize - -#include -#define __USE_GNU -#include -#include -#include -#include -#include -#include -#include -#include /* for poll */ -#include /* for mmap */ -#include -#include -#include /* for waitpid macros */ - -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "restart.h" -#include "semaphore.h" -#include "debug.h" /* PDEBUG, added by StS */ - - -/* poll() is not supported in kernel <= 2.0, therefore is __NR_poll is - * not available, we assume an old Linux kernel is in use and we will - * use select() instead. */ -#include -#ifndef __NR_poll -# define USE_SELECT -#endif - - -/* Array of active threads. Entry 0 is reserved for the initial thread. */ -struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] = -{ { __LOCK_INITIALIZER, &__pthread_initial_thread, 0}, - { __LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ }; - -/* For debugging purposes put the maximum number of threads in a variable. */ -const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX; - -/* Indicate whether at least one thread has a user-defined stack (if 1), - or if all threads have stacks supplied by LinuxThreads (if 0). */ -int __pthread_nonstandard_stacks; - -/* Number of active entries in __pthread_handles (used by gdb) */ -volatile int __pthread_handles_num = 2; - -/* Whether to use debugger additional actions for thread creation - (set to 1 by gdb) */ -volatile int __pthread_threads_debug; - -/* Globally enabled events. */ -volatile td_thr_events_t __pthread_threads_events; - -/* Pointer to thread descriptor with last event. */ -volatile pthread_descr __pthread_last_event; - -/* Mapping from stack segment to thread descriptor. */ -/* Stack segment numbers are also indices into the __pthread_handles array. */ -/* Stack segment number 0 is reserved for the initial thread. */ - -static inline pthread_descr thread_segment(int seg) -{ - return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE) - - 1; -} - -/* Flag set in signal handler to record child termination */ - -static volatile int terminated_children = 0; - -/* Flag set when the initial thread is blocked on pthread_exit waiting - for all other threads to terminate */ - -static int main_thread_exiting = 0; - -/* Counter used to generate unique thread identifier. - Thread identifier is pthread_threads_counter + segment. */ - -static pthread_t pthread_threads_counter = 0; - -/* Forward declarations */ - -static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, - void * (*start_routine)(void *), void *arg, - sigset_t *mask, int father_pid, - int report_events, - td_thr_events_t *event_maskp); -static void pthread_handle_free(pthread_t th_id); -static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode); -static void pthread_reap_children(void); -static void pthread_kill_all_threads(int sig, int main_thread_also); - -/* The server thread managing requests for thread creation and termination */ - -int __pthread_manager(void *arg) -{ - int reqfd = (int) (long int) arg; -#ifdef USE_SELECT - struct timeval tv; - fd_set fd; -#else - struct pollfd ufd; -#endif - sigset_t manager_mask; - int n; - struct pthread_request request; - - /* If we have special thread_self processing, initialize it. */ -#ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(&__pthread_manager_thread, 1); -#endif - /* Set the error variable. */ - __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno; - __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno; - -#ifdef __UCLIBC_HAS_XLOCALE__ - /* Initialize thread's locale to the global locale. */ - __pthread_manager_thread.locale = __global_locale; -#endif /* __UCLIBC_HAS_XLOCALE__ */ - - /* Block all signals except __pthread_sig_cancel and SIGTRAP */ - sigfillset(&manager_mask); - sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */ - sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */ - if (__pthread_threads_debug && __pthread_sig_debug > 0) - sigdelset(&manager_mask, __pthread_sig_debug); - sigprocmask(SIG_SETMASK, &manager_mask, NULL); - /* Raise our priority to match that of main thread */ - __pthread_manager_adjust_prio(__pthread_main_thread->p_priority); - /* Synchronize debugging of the thread manager */ - n = TEMP_FAILURE_RETRY(__libc_read(reqfd, (char *)&request, - sizeof(request))); - ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG); -#ifndef USE_SELECT - ufd.fd = reqfd; - ufd.events = POLLIN; -#endif - /* Enter server loop */ - while(1) { -#ifdef USE_SELECT - tv.tv_sec = 2; - tv.tv_usec = 0; - FD_ZERO (&fd); - FD_SET (reqfd, &fd); - n = select (reqfd + 1, &fd, NULL, NULL, &tv); -#else - PDEBUG("before poll\n"); - n = poll(&ufd, 1, 2000); - PDEBUG("after poll\n"); -#endif - /* Check for termination of the main thread */ - if (getppid() == 1) { - pthread_kill_all_threads(SIGKILL, 0); - _exit(0); - } - /* Check for dead children */ - if (terminated_children) { - terminated_children = 0; - pthread_reap_children(); - } - /* Read and execute request */ -#ifdef USE_SELECT - if (n == 1) -#else - if (n == 1 && (ufd.revents & POLLIN)) -#endif - { - - PDEBUG("before __libc_read\n"); - n = __libc_read(reqfd, (char *)&request, sizeof(request)); - PDEBUG("after __libc_read, n=%d\n", n); - ASSERT(n == sizeof(request)); - switch(request.req_kind) { - case REQ_CREATE: - PDEBUG("got REQ_CREATE\n"); - request.req_thread->p_retcode = - pthread_handle_create((pthread_t *) &request.req_thread->p_retval, - request.req_args.create.attr, - request.req_args.create.fn, - request.req_args.create.arg, - &request.req_args.create.mask, - request.req_thread->p_pid, - request.req_thread->p_report_events, - &request.req_thread->p_eventbuf.eventmask); - PDEBUG("restarting %d\n", request.req_thread); - restart(request.req_thread); - break; - case REQ_FREE: - PDEBUG("got REQ_FREE\n"); - pthread_handle_free(request.req_args.free.thread_id); - break; - case REQ_PROCESS_EXIT: - PDEBUG("got REQ_PROCESS_EXIT from %d, exit code = %d\n", - request.req_thread, request.req_args.exit.code); - pthread_handle_exit(request.req_thread, - request.req_args.exit.code); - break; - case REQ_MAIN_THREAD_EXIT: - PDEBUG("got REQ_MAIN_THREAD_EXIT\n"); - main_thread_exiting = 1; - /* Reap children in case all other threads died and the signal handler - went off before we set main_thread_exiting to 1, and therefore did - not do REQ_KICK. */ - pthread_reap_children(); - - if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { - restart(__pthread_main_thread); - /* The main thread will now call exit() which will trigger an - __on_exit handler, which in turn will send REQ_PROCESS_EXIT - to the thread manager. In case you are wondering how the - manager terminates from its loop here. */ - } - break; - case REQ_POST: - PDEBUG("got REQ_POST\n"); - __new_sem_post(request.req_args.post); - break; - case REQ_DEBUG: - PDEBUG("got REQ_DEBUG\n"); - /* Make gdb aware of new thread and gdb will restart the - new thread when it is ready to handle the new thread. */ - if (__pthread_threads_debug && __pthread_sig_debug > 0) { - PDEBUG("about to call raise(__pthread_sig_debug)\n"); - raise(__pthread_sig_debug); - } - case REQ_KICK: - /* This is just a prod to get the manager to reap some - threads right away, avoiding a potential delay at shutdown. */ - break; - } - } - } -} - -int __pthread_manager_event(void *arg) -{ - /* If we have special thread_self processing, initialize it. */ -#ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(&__pthread_manager_thread, 1); -#endif - - /* Get the lock the manager will free once all is correctly set up. */ - __pthread_lock (THREAD_GETMEM((&__pthread_manager_thread), p_lock), NULL); - /* Free it immediately. */ - __pthread_unlock (THREAD_GETMEM((&__pthread_manager_thread), p_lock)); - - return __pthread_manager(arg); -} - -/* Process creation */ -static int -__attribute__ ((noreturn)) -pthread_start_thread(void *arg) -{ - pthread_descr self = (pthread_descr) arg; - struct pthread_request request; - void * outcome; - /* Initialize special thread_self processing, if any. */ -#ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(self, self->p_nr); -#endif - PDEBUG("\n"); - /* Make sure our pid field is initialized, just in case we get there - before our father has initialized it. */ - THREAD_SETMEM(self, p_pid, __getpid()); - /* Initial signal mask is that of the creating thread. (Otherwise, - we'd just inherit the mask of the thread manager.) */ - sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); - /* Set the scheduling policy and priority for the new thread, if needed */ - if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) - /* Explicit scheduling attributes were provided: apply them */ - sched_setscheduler(THREAD_GETMEM(self, p_pid), - THREAD_GETMEM(self, p_start_args.schedpolicy), - &self->p_start_args.schedparam); - else if (__pthread_manager_thread.p_priority > 0) - /* Default scheduling required, but thread manager runs in realtime - scheduling: switch new thread to SCHED_OTHER policy */ - { - struct sched_param default_params; - default_params.sched_priority = 0; - sched_setscheduler(THREAD_GETMEM(self, p_pid), - SCHED_OTHER, &default_params); - } - /* Make gdb aware of new thread */ - if (__pthread_threads_debug && __pthread_sig_debug > 0) { - request.req_thread = self; - request.req_kind = REQ_DEBUG; - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *) &request, sizeof(request))); - suspend(self); - } - /* Run the thread code */ - outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, - p_start_args.arg)); - /* Exit with the given return value */ - pthread_exit(outcome); -} - -static int -__attribute__ ((noreturn)) -pthread_start_thread_event(void *arg) -{ - pthread_descr self = (pthread_descr) arg; - -#ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(self, self->p_nr); -#endif - /* Make sure our pid field is initialized, just in case we get there - before our father has initialized it. */ - THREAD_SETMEM(self, p_pid, __getpid()); - /* Get the lock the manager will free once all is correctly set up. */ - __pthread_lock (THREAD_GETMEM(self, p_lock), NULL); - /* Free it immediately. */ - __pthread_unlock (THREAD_GETMEM(self, p_lock)); - - /* Continue with the real function. */ - pthread_start_thread (arg); -} - -static int pthread_allocate_stack(const pthread_attr_t *attr, - pthread_descr default_new_thread, - int pagesize, - pthread_descr * out_new_thread, - char ** out_new_thread_bottom, - char ** out_guardaddr, - size_t * out_guardsize) -{ - pthread_descr new_thread; - char * new_thread_bottom; - char * guardaddr; - size_t stacksize, guardsize; - - if (attr != NULL && attr->__stackaddr_set) - { - /* The user provided a stack. */ - new_thread = - (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1; - new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize; - guardaddr = NULL; - guardsize = 0; - __pthread_nonstandard_stacks = 1; - } - else - { -#ifdef __ARCH_HAS_MMU__ - stacksize = STACK_SIZE - pagesize; - if (attr != NULL) - stacksize = MIN (stacksize, roundup(attr->__stacksize, pagesize)); - /* Allocate space for stack and thread descriptor at default address */ - new_thread = default_new_thread; - new_thread_bottom = (char *) (new_thread + 1) - stacksize; - if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE), - INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, - -1, 0) == MAP_FAILED) - /* Bad luck, this segment is already mapped. */ - return -1; - /* We manage to get a stack. Now see whether we need a guard - and allocate it if necessary. Notice that the default - attributes (stack_size = STACK_SIZE - pagesize) do not need - a guard page, since the RLIMIT_STACK soft limit prevents stacks - from running into one another. */ - if (stacksize == STACK_SIZE - pagesize) - { - /* We don't need a guard page. */ - guardaddr = NULL; - guardsize = 0; - } - else - { - /* Put a bad page at the bottom of the stack */ - guardsize = attr->__guardsize; - guardaddr = (void *)new_thread_bottom - guardsize; - if (mmap ((caddr_t) guardaddr, guardsize, 0, MAP_FIXED, -1, 0) - == MAP_FAILED) - { - /* We don't make this an error. */ - guardaddr = NULL; - guardsize = 0; - } - } -#else - /* We cannot mmap to this huge chunk of stack space when we don't have - * an MMU. Pretend we are using a user provided stack even if there was - * none provided by the user. Thus, we get around the mmap and reservation - * of a huge stack segment. -StS */ - - stacksize = INITIAL_STACK_SIZE; - /* The user may want to use a non-default stacksize */ - if (attr != NULL) - { - stacksize = attr->__stacksize; - } - - /* malloc a stack - memory from the bottom up */ - if ((new_thread_bottom = malloc(stacksize)) == NULL) - { - /* bad luck, we cannot malloc any more */ - return -1 ; - } - PDEBUG("malloced chunk: base=%p, size=0x%04x\n", new_thread_bottom, stacksize); - - /* Set up the pointers. new_thread marks the TOP of the stack frame and - * the address of the pthread_descr struct at the same time. Therefore we - * must account for its size and fit it in the malloc()'ed block. The - * value of `new_thread' is then passed to clone() as the stack argument. - * - * ^ +------------------------+ - * | | pthread_descr struct | - * | +------------------------+ <- new_thread - * malloc block | | | - * | | thread stack | - * | | | - * v +------------------------+ <- new_thread_bottom - * - * Note: The calculated value of new_thread must be word aligned otherwise - * the kernel chokes on a non-aligned stack frame. Choose the lower - * available word boundary. - */ - new_thread = ((pthread_descr) ((int)(new_thread_bottom + stacksize) & -sizeof(void*))) - 1; - guardaddr = NULL; - guardsize = 0; - - PDEBUG("thread stack: bos=%p, tos=%p\n", new_thread_bottom, new_thread); - - /* check the initial thread stack boundaries so they don't overlap */ - NOMMU_INITIAL_THREAD_BOUNDS((char *) new_thread, (char *) new_thread_bottom); - - PDEBUG("initial stack: bos=%p, tos=%p\n", __pthread_initial_thread_bos, - __pthread_initial_thread_tos); - - /* on non-MMU systems we always have non-standard stack frames */ - __pthread_nonstandard_stacks = 1; - -#endif /* __ARCH_HAS_MMU__ */ - } - - /* Clear the thread data structure. */ - memset (new_thread, '\0', sizeof (*new_thread)); - *out_new_thread = new_thread; - *out_new_thread_bottom = new_thread_bottom; - *out_guardaddr = guardaddr; - *out_guardsize = guardsize; - return 0; -} - -static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, - void * (*start_routine)(void *), void *arg, - sigset_t * mask, int father_pid, - int report_events, - td_thr_events_t *event_maskp) -{ - size_t sseg; - int pid; - pthread_descr new_thread; - char * new_thread_bottom; - pthread_t new_thread_id; - char *guardaddr = NULL; - size_t guardsize = 0; - int pagesize = __getpagesize(); - int saved_errno = 0; - - /* First check whether we have to change the policy and if yes, whether - we can do this. Normally this should be done by examining the - return value of the sched_setscheduler call in pthread_start_thread - but this is hard to implement. FIXME */ - if (attr != NULL && attr->__schedpolicy != SCHED_OTHER && geteuid () != 0) - return EPERM; - /* Find a free segment for the thread, and allocate a stack if needed */ - for (sseg = 2; ; sseg++) - { - if (sseg >= PTHREAD_THREADS_MAX) - return EAGAIN; - if (__pthread_handles[sseg].h_descr != NULL) - continue; - if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize, - &new_thread, &new_thread_bottom, - &guardaddr, &guardsize) == 0) - break; - } - __pthread_handles_num++; - /* Allocate new thread identifier */ - pthread_threads_counter += PTHREAD_THREADS_MAX; - new_thread_id = sseg + pthread_threads_counter; - /* Initialize the thread descriptor. Elements which have to be - initialized to zero already have this value. */ - new_thread->p_tid = new_thread_id; - new_thread->p_lock = &(__pthread_handles[sseg].h_lock); - new_thread->p_cancelstate = PTHREAD_CANCEL_ENABLE; - new_thread->p_canceltype = PTHREAD_CANCEL_DEFERRED; - new_thread->p_errnop = &new_thread->p_errno; - new_thread->p_h_errnop = &new_thread->p_h_errno; -#ifdef __UCLIBC_HAS_XLOCALE__ - /* Initialize thread's locale to the global locale. */ - new_thread->locale = __global_locale; -#endif /* __UCLIBC_HAS_XLOCALE__ */ - new_thread->p_guardaddr = guardaddr; - new_thread->p_guardsize = guardsize; - new_thread->p_self = new_thread; - new_thread->p_nr = sseg; - /* Initialize the thread handle */ - __pthread_init_lock(&__pthread_handles[sseg].h_lock); - __pthread_handles[sseg].h_descr = new_thread; - __pthread_handles[sseg].h_bottom = new_thread_bottom; - /* Determine scheduling parameters for the thread */ - new_thread->p_start_args.schedpolicy = -1; - if (attr != NULL) { - new_thread->p_detached = attr->__detachstate; - new_thread->p_userstack = attr->__stackaddr_set; - - switch(attr->__inheritsched) { - case PTHREAD_EXPLICIT_SCHED: - new_thread->p_start_args.schedpolicy = attr->__schedpolicy; - memcpy (&new_thread->p_start_args.schedparam, &attr->__schedparam, - sizeof (struct sched_param)); - break; - case PTHREAD_INHERIT_SCHED: - new_thread->p_start_args.schedpolicy = sched_getscheduler(father_pid); - sched_getparam(father_pid, &new_thread->p_start_args.schedparam); - break; - } - new_thread->p_priority = - new_thread->p_start_args.schedparam.sched_priority; - } - /* Finish setting up arguments to pthread_start_thread */ - new_thread->p_start_args.start_routine = start_routine; - new_thread->p_start_args.arg = arg; - new_thread->p_start_args.mask = *mask; - /* Raise priority of thread manager if needed */ - __pthread_manager_adjust_prio(new_thread->p_priority); - /* Do the cloning. We have to use two different functions depending - on whether we are debugging or not. */ - pid = 0; /* Note that the thread never can have PID zero. */ - - - /* ******************************************************** */ - /* This code was moved from below to cope with running threads - * on uClinux systems. See comment below... - * Insert new thread in doubly linked list of active threads */ - new_thread->p_prevlive = __pthread_main_thread; - new_thread->p_nextlive = __pthread_main_thread->p_nextlive; - __pthread_main_thread->p_nextlive->p_prevlive = new_thread; - __pthread_main_thread->p_nextlive = new_thread; - /* ********************************************************* */ - - if (report_events) - { - /* See whether the TD_CREATE event bit is set in any of the - masks. */ - int idx = __td_eventword (TD_CREATE); - uint32_t mask = __td_eventmask (TD_CREATE); - - if ((mask & (__pthread_threads_events.event_bits[idx] - | event_maskp->event_bits[idx])) != 0) - { - /* Lock the mutex the child will use now so that it will stop. */ - __pthread_lock(new_thread->p_lock, NULL); - - /* We have to report this event. */ - pid = clone(pthread_start_thread_event, (void **) new_thread, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | - __pthread_sig_cancel, new_thread); - - saved_errno = errno; - if (pid != -1) - { - /* Now fill in the information about the new thread in - the newly created thread's data structure. We cannot let - the new thread do this since we don't know whether it was - already scheduled when we send the event. */ - new_thread->p_eventbuf.eventdata = new_thread; - new_thread->p_eventbuf.eventnum = TD_CREATE; - __pthread_last_event = new_thread; - - /* We have to set the PID here since the callback function - in the debug library will need it and we cannot guarantee - the child got scheduled before the debugger. */ - new_thread->p_pid = pid; - - /* Now call the function which signals the event. */ - __linuxthreads_create_event (); - - /* Now restart the thread. */ - __pthread_unlock(new_thread->p_lock); - } - } - } - if (pid == 0) - { - PDEBUG("cloning new_thread = %p\n", new_thread); - pid = clone(pthread_start_thread, (void **) new_thread, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | - __pthread_sig_cancel, new_thread); - saved_errno = errno; - } - /* Check if cloning succeeded */ - if (pid == -1) { - /******************************************************** - * Code inserted to remove the thread from our list of active - * threads in case of failure (needed to cope with uClinux), - * See comment below. */ - new_thread->p_nextlive->p_prevlive = new_thread->p_prevlive; - new_thread->p_prevlive->p_nextlive = new_thread->p_nextlive; - /********************************************************/ - - /* Free the stack if we allocated it */ - if (attr == NULL || !attr->__stackaddr_set) - { -#ifdef __ARCH_HAS_MMU__ - if (new_thread->p_guardsize != 0) - munmap(new_thread->p_guardaddr, new_thread->p_guardsize); - munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE), - INITIAL_STACK_SIZE); -#else - free(new_thread_bottom); -#endif /* __ARCH_HAS_MMU__ */ - } - __pthread_handles[sseg].h_descr = NULL; - __pthread_handles[sseg].h_bottom = NULL; - __pthread_handles_num--; - return errno; - } - PDEBUG("new thread pid = %d\n", pid); - -#if 0 - /* *********************************************************** - This code has been moved before the call to clone(). In uClinux, - the use of wait on a semaphore is dependant upon that the child so - the child must be in the active threads list. This list is used in - pthread_find_self() to get the pthread_descr of self. So, if the - child calls sem_wait before this code is executed , it will hang - forever and initial_thread will instead be posted by a sem_post - call. */ - - /* Insert new thread in doubly linked list of active threads */ - new_thread->p_prevlive = __pthread_main_thread; - new_thread->p_nextlive = __pthread_main_thread->p_nextlive; - __pthread_main_thread->p_nextlive->p_prevlive = new_thread; - __pthread_main_thread->p_nextlive = new_thread; - /************************************************************/ -#endif - - /* Set pid field of the new thread, in case we get there before the - child starts. */ - new_thread->p_pid = pid; - /* We're all set */ - *thread = new_thread_id; - return 0; -} - - -/* Try to free the resources of a thread when requested by pthread_join - or pthread_detach on a terminated thread. */ - -static void pthread_free(pthread_descr th) -{ - pthread_handle handle; - pthread_readlock_info *iter, *next; - char *h_bottom_save; - - ASSERT(th->p_exited); - /* Make the handle invalid */ - handle = thread_handle(th->p_tid); - __pthread_lock(&handle->h_lock, NULL); - h_bottom_save = handle->h_bottom; - handle->h_descr = NULL; - handle->h_bottom = (char *)(-1L); - __pthread_unlock(&handle->h_lock); -#ifdef FREE_THREAD_SELF - FREE_THREAD_SELF(th, th->p_nr); -#endif - /* One fewer threads in __pthread_handles */ - __pthread_handles_num--; - - /* Destroy read lock list, and list of free read lock structures. - If the former is not empty, it means the thread exited while - holding read locks! */ - - for (iter = th->p_readlock_list; iter != NULL; iter = next) - { - next = iter->pr_next; - free(iter); - } - - for (iter = th->p_readlock_free; iter != NULL; iter = next) - { - next = iter->pr_next; - free(iter); - } - - /* If initial thread, nothing to free */ - if (th == &__pthread_initial_thread) return; -#ifdef __ARCH_HAS_MMU__ - if (!th->p_userstack) - { - /* Free the stack and thread descriptor area */ - if (th->p_guardsize != 0) - munmap(th->p_guardaddr, th->p_guardsize); - munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE); - } -#else - /* For non-MMU systems we always malloc the stack, so free it here. -StS */ - if (!th->p_userstack) { - free(h_bottom_save); - } -#endif /* __ARCH_HAS_MMU__ */ -} - -/* Handle threads that have exited */ - -static void pthread_exited(pid_t pid) -{ - pthread_descr th; - int detached; - /* Find thread with that pid */ - for (th = __pthread_main_thread->p_nextlive; - th != __pthread_main_thread; - th = th->p_nextlive) { - if (th->p_pid == pid) { - /* Remove thread from list of active threads */ - th->p_nextlive->p_prevlive = th->p_prevlive; - th->p_prevlive->p_nextlive = th->p_nextlive; - /* Mark thread as exited, and if detached, free its resources */ - __pthread_lock(th->p_lock, NULL); - th->p_exited = 1; - /* If we have to signal this event do it now. */ - if (th->p_report_events) - { - /* See whether TD_REAP is in any of the mask. */ - int idx = __td_eventword (TD_REAP); - uint32_t mask = __td_eventmask (TD_REAP); - - if ((mask & (__pthread_threads_events.event_bits[idx] - | th->p_eventbuf.eventmask.event_bits[idx])) != 0) - { - /* Yep, we have to signal the reapage. */ - th->p_eventbuf.eventnum = TD_REAP; - th->p_eventbuf.eventdata = th; - __pthread_last_event = th; - - /* Now call the function to signal the event. */ - __linuxthreads_reap_event(); - } - } - detached = th->p_detached; - __pthread_unlock(th->p_lock); - if (detached) - pthread_free(th); - break; - } - } - /* If all threads have exited and the main thread is pending on a - pthread_exit, wake up the main thread and terminate ourselves. */ - if (main_thread_exiting && - __pthread_main_thread->p_nextlive == __pthread_main_thread) { - restart(__pthread_main_thread); - /* Same logic as REQ_MAIN_THREAD_EXIT. */ - } -} - -static void pthread_reap_children(void) -{ - pid_t pid; - int status; - PDEBUG("\n"); - - while ((pid = __libc_waitpid(-1, &status, WNOHANG | __WCLONE)) > 0) { - pthread_exited(pid); - if (WIFSIGNALED(status)) { - /* If a thread died due to a signal, send the same signal to - all other threads, including the main thread. */ - pthread_kill_all_threads(WTERMSIG(status), 1); - _exit(0); - } - } -} - -/* Try to free the resources of a thread when requested by pthread_join - or pthread_detach on a terminated thread. */ - -static void pthread_handle_free(pthread_t th_id) -{ - pthread_handle handle = thread_handle(th_id); - pthread_descr th; - - __pthread_lock(&handle->h_lock, NULL); - if (invalid_handle(handle, th_id)) { - /* pthread_reap_children has deallocated the thread already, - nothing needs to be done */ - __pthread_unlock(&handle->h_lock); - return; - } - th = handle->h_descr; - if (th->p_exited) { - __pthread_unlock(&handle->h_lock); - pthread_free(th); - } else { - /* The Unix process of the thread is still running. - Mark the thread as detached so that the thread manager will - deallocate its resources when the Unix process exits. */ - th->p_detached = 1; - __pthread_unlock(&handle->h_lock); - } -} - -/* Send a signal to all running threads */ - -static void pthread_kill_all_threads(int sig, int main_thread_also) -{ - pthread_descr th; - for (th = __pthread_main_thread->p_nextlive; - th != __pthread_main_thread; - th = th->p_nextlive) { - kill(th->p_pid, sig); - } - if (main_thread_also) { - kill(__pthread_main_thread->p_pid, sig); - } -} - -/* Process-wide exit() */ - -static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode) -{ - pthread_descr th; - __pthread_exit_requested = 1; - __pthread_exit_code = exitcode; - /* Send the CANCEL signal to all running threads, including the main - thread, but excluding the thread from which the exit request originated - (that thread must complete the exit, e.g. calling atexit functions - and flushing stdio buffers). */ - for (th = issuing_thread->p_nextlive; - th != issuing_thread; - th = th->p_nextlive) { - kill(th->p_pid, __pthread_sig_cancel); - } - /* Now, wait for all these threads, so that they don't become zombies - and their times are properly added to the thread manager's times. */ - for (th = issuing_thread->p_nextlive; - th != issuing_thread; - th = th->p_nextlive) { - waitpid(th->p_pid, NULL, __WCLONE); - } - restart(issuing_thread); - _exit(0); -} - -/* Handler for __pthread_sig_cancel in thread manager thread */ - -void __pthread_manager_sighandler(int sig) -{ - int kick_manager = terminated_children == 0 && main_thread_exiting; - terminated_children = 1; - - /* If the main thread is terminating, kick the thread manager loop - each time some threads terminate. This eliminates a two second - shutdown delay caused by the thread manager sleeping in the - call to __poll(). Instead, the thread manager is kicked into - action, reaps the outstanding threads and resumes the main thread - so that it can complete the shutdown. */ - - if (kick_manager) { - struct pthread_request request; - request.req_thread = 0; - request.req_kind = REQ_KICK; - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *) &request, sizeof(request))); - } -} - -/* Adjust priority of thread manager so that it always run at a priority - higher than all threads */ - -void __pthread_manager_adjust_prio(int thread_prio) -{ - struct sched_param param; - - if (thread_prio <= __pthread_manager_thread.p_priority) return; - param.sched_priority = - thread_prio < sched_get_priority_max(SCHED_FIFO) - ? thread_prio + 1 : thread_prio; - sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, ¶m); - __pthread_manager_thread.p_priority = thread_prio; -} diff --git a/libpthread/linuxthreads/mutex.c b/libpthread/linuxthreads/mutex.c deleted file mode 100644 index 7cc344fac..000000000 --- a/libpthread/linuxthreads/mutex.c +++ /dev/null @@ -1,356 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Mutexes */ - -#include -#include -#include -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "queue.h" -#include "restart.h" - -int __pthread_mutex_init(pthread_mutex_t * mutex, - const pthread_mutexattr_t * mutex_attr) -{ - __pthread_init_lock(&mutex->__m_lock); - mutex->__m_kind = - mutex_attr == NULL ? PTHREAD_MUTEX_TIMED_NP : mutex_attr->__mutexkind; - mutex->__m_count = 0; - mutex->__m_owner = NULL; - return 0; -} -strong_alias (__pthread_mutex_init, pthread_mutex_init) - -int __pthread_mutex_destroy(pthread_mutex_t * mutex) -{ - switch (mutex->__m_kind) { - case PTHREAD_MUTEX_ADAPTIVE_NP: - case PTHREAD_MUTEX_RECURSIVE_NP: - if ((mutex->__m_lock.__status & 1) != 0) - return EBUSY; - return 0; - case PTHREAD_MUTEX_ERRORCHECK_NP: - case PTHREAD_MUTEX_TIMED_NP: - if (mutex->__m_lock.__status != 0) - return EBUSY; - return 0; - default: - return EINVAL; - } -} -strong_alias (__pthread_mutex_destroy, pthread_mutex_destroy) - -int __pthread_mutex_trylock(pthread_mutex_t * mutex) -{ - pthread_descr self; - int retcode; - - switch(mutex->__m_kind) { - case PTHREAD_MUTEX_ADAPTIVE_NP: - retcode = __pthread_trylock(&mutex->__m_lock); - return retcode; - case PTHREAD_MUTEX_RECURSIVE_NP: - self = thread_self(); - if (mutex->__m_owner == self) { - mutex->__m_count++; - return 0; - } - retcode = __pthread_trylock(&mutex->__m_lock); - if (retcode == 0) { - mutex->__m_owner = self; - mutex->__m_count = 0; - } - return retcode; - case PTHREAD_MUTEX_ERRORCHECK_NP: - retcode = __pthread_alt_trylock(&mutex->__m_lock); - if (retcode == 0) { - mutex->__m_owner = thread_self(); - } - return retcode; - case PTHREAD_MUTEX_TIMED_NP: - retcode = __pthread_alt_trylock(&mutex->__m_lock); - return retcode; - default: - return EINVAL; - } -} -strong_alias (__pthread_mutex_trylock, pthread_mutex_trylock) - -int __pthread_mutex_lock(pthread_mutex_t * mutex) -{ - pthread_descr self; - - switch(mutex->__m_kind) { - case PTHREAD_MUTEX_ADAPTIVE_NP: - __pthread_lock(&mutex->__m_lock, NULL); - return 0; - case PTHREAD_MUTEX_RECURSIVE_NP: - self = thread_self(); - if (mutex->__m_owner == self) { - mutex->__m_count++; - return 0; - } - __pthread_lock(&mutex->__m_lock, self); - mutex->__m_owner = self; - mutex->__m_count = 0; - return 0; - case PTHREAD_MUTEX_ERRORCHECK_NP: - self = thread_self(); - if (mutex->__m_owner == self) return EDEADLK; - __pthread_alt_lock(&mutex->__m_lock, self); - mutex->__m_owner = self; - return 0; - case PTHREAD_MUTEX_TIMED_NP: - __pthread_alt_lock(&mutex->__m_lock, NULL); - return 0; - default: - return EINVAL; - } -} -strong_alias (__pthread_mutex_lock, pthread_mutex_lock) - -int __pthread_mutex_timedlock (pthread_mutex_t *mutex, - const struct timespec *abstime) -{ - pthread_descr self; - int res; - - if (__builtin_expect (abstime->tv_nsec, 0) < 0 - || __builtin_expect (abstime->tv_nsec, 0) >= 1000000000) - return EINVAL; - - switch(mutex->__m_kind) { - case PTHREAD_MUTEX_ADAPTIVE_NP: - __pthread_lock(&mutex->__m_lock, NULL); - return 0; - case PTHREAD_MUTEX_RECURSIVE_NP: - self = thread_self(); - if (mutex->__m_owner == self) { - mutex->__m_count++; - return 0; - } - __pthread_lock(&mutex->__m_lock, self); - mutex->__m_owner = self; - mutex->__m_count = 0; - return 0; - case PTHREAD_MUTEX_ERRORCHECK_NP: - self = thread_self(); - if (mutex->__m_owner == self) return EDEADLK; - res = __pthread_alt_timedlock(&mutex->__m_lock, self, abstime); - if (res != 0) - { - mutex->__m_owner = self; - return 0; - } - return ETIMEDOUT; - case PTHREAD_MUTEX_TIMED_NP: - /* Only this type supports timed out lock. */ - return (__pthread_alt_timedlock(&mutex->__m_lock, NULL, abstime) - ? 0 : ETIMEDOUT); - default: - return EINVAL; - } -} -strong_alias (__pthread_mutex_timedlock, pthread_mutex_timedlock) - -int __pthread_mutex_unlock(pthread_mutex_t * mutex) -{ - switch (mutex->__m_kind) { - case PTHREAD_MUTEX_ADAPTIVE_NP: - __pthread_unlock(&mutex->__m_lock); - return 0; - case PTHREAD_MUTEX_RECURSIVE_NP: - if (mutex->__m_owner != thread_self()) - return EPERM; - if (mutex->__m_count > 0) { - mutex->__m_count--; - return 0; - } - mutex->__m_owner = NULL; - __pthread_unlock(&mutex->__m_lock); - return 0; - case PTHREAD_MUTEX_ERRORCHECK_NP: - if (mutex->__m_owner != thread_self() || mutex->__m_lock.__status == 0) - return EPERM; - mutex->__m_owner = NULL; - __pthread_alt_unlock(&mutex->__m_lock); - return 0; - case PTHREAD_MUTEX_TIMED_NP: - __pthread_alt_unlock(&mutex->__m_lock); - return 0; - default: - return EINVAL; - } -} -strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock) - -int __pthread_mutexattr_init(pthread_mutexattr_t *attr) -{ - attr->__mutexkind = PTHREAD_MUTEX_TIMED_NP; - return 0; -} -strong_alias (__pthread_mutexattr_init, pthread_mutexattr_init) - -int __pthread_mutexattr_destroy(pthread_mutexattr_t *attr) -{ - return 0; -} -strong_alias (__pthread_mutexattr_destroy, pthread_mutexattr_destroy) - -int __pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind) -{ - if (kind != PTHREAD_MUTEX_ADAPTIVE_NP - && kind != PTHREAD_MUTEX_RECURSIVE_NP - && kind != PTHREAD_MUTEX_ERRORCHECK_NP - && kind != PTHREAD_MUTEX_TIMED_NP) - return EINVAL; - attr->__mutexkind = kind; - return 0; -} -weak_alias (__pthread_mutexattr_settype, pthread_mutexattr_settype) -strong_alias ( __pthread_mutexattr_settype, __pthread_mutexattr_setkind_np) -weak_alias (__pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np) - -int __pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind) -{ - *kind = attr->__mutexkind; - return 0; -} -weak_alias (__pthread_mutexattr_gettype, pthread_mutexattr_gettype) -strong_alias (__pthread_mutexattr_gettype, __pthread_mutexattr_getkind_np) -weak_alias (__pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np) - -int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *attr, - int *pshared) -{ - *pshared = PTHREAD_PROCESS_PRIVATE; - return 0; -} -weak_alias (__pthread_mutexattr_getpshared, pthread_mutexattr_getpshared) - -int __pthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int pshared) -{ - if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) - return EINVAL; - - /* For now it is not possible to shared a conditional variable. */ - if (pshared != PTHREAD_PROCESS_PRIVATE) - return ENOSYS; - - return 0; -} -weak_alias (__pthread_mutexattr_setpshared, pthread_mutexattr_setpshared) - -/* Once-only execution */ - -static pthread_mutex_t once_masterlock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t once_finished = PTHREAD_COND_INITIALIZER; -static int fork_generation = 0; /* Child process increments this after fork. */ - -enum { NEVER = 0, IN_PROGRESS = 1, DONE = 2 }; - -/* If a thread is canceled while calling the init_routine out of - pthread once, this handler will reset the once_control variable - to the NEVER state. */ - -static void pthread_once_cancelhandler(void *arg) -{ - pthread_once_t *once_control = arg; - - pthread_mutex_lock(&once_masterlock); - *once_control = NEVER; - pthread_mutex_unlock(&once_masterlock); - pthread_cond_broadcast(&once_finished); -} - -int __pthread_once(pthread_once_t * once_control, void (*init_routine)(void)) -{ - /* flag for doing the condition broadcast outside of mutex */ - int state_changed; - - /* Test without locking first for speed */ - if (*once_control == DONE) { - READ_MEMORY_BARRIER(); - return 0; - } - /* Lock and test again */ - - state_changed = 0; - - pthread_mutex_lock(&once_masterlock); - - /* If this object was left in an IN_PROGRESS state in a parent - process (indicated by stale generation field), reset it to NEVER. */ - if ((*once_control & 3) == IN_PROGRESS && (*once_control & ~3) != fork_generation) - *once_control = NEVER; - - /* If init_routine is being called from another routine, wait until - it completes. */ - while ((*once_control & 3) == IN_PROGRESS) { - pthread_cond_wait(&once_finished, &once_masterlock); - } - /* Here *once_control is stable and either NEVER or DONE. */ - if (*once_control == NEVER) { - *once_control = IN_PROGRESS | fork_generation; - pthread_mutex_unlock(&once_masterlock); - pthread_cleanup_push(pthread_once_cancelhandler, once_control); - init_routine(); - pthread_cleanup_pop(0); - pthread_mutex_lock(&once_masterlock); - WRITE_MEMORY_BARRIER(); - *once_control = DONE; - state_changed = 1; - } - pthread_mutex_unlock(&once_masterlock); - - if (state_changed) - pthread_cond_broadcast(&once_finished); - - return 0; -} -strong_alias (__pthread_once, pthread_once) - -/* - * Handle the state of the pthread_once mechanism across forks. The - * once_masterlock is acquired in the parent process prior to a fork to ensure - * that no thread is in the critical region protected by the lock. After the - * fork, the lock is released. In the child, the lock and the condition - * variable are simply reset. The child also increments its generation - * counter which lets pthread_once calls detect stale IN_PROGRESS states - * and reset them back to NEVER. - */ - -void __pthread_once_fork_prepare(void) -{ - pthread_mutex_lock(&once_masterlock); -} - -void __pthread_once_fork_parent(void) -{ - pthread_mutex_unlock(&once_masterlock); -} - -void __pthread_once_fork_child(void) -{ - pthread_mutex_init(&once_masterlock, NULL); - pthread_cond_init(&once_finished, NULL); - if (fork_generation <= INT_MAX - 4) - fork_generation += 4; /* leave least significant two bits zero */ - else - fork_generation = 0; -} diff --git a/libpthread/linuxthreads/oldsemaphore.c b/libpthread/linuxthreads/oldsemaphore.c deleted file mode 100644 index 3a3b3d186..000000000 --- a/libpthread/linuxthreads/oldsemaphore.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * This file contains the old semaphore code that we need to - * preserve for glibc-2.0 backwards compatibility. Port to glibc 2.1 - * done by Cristian Gafton. - */ - -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Semaphores a la POSIX 1003.1b */ - -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "restart.h" -#include "queue.h" - -typedef struct { - long int sem_status; - int sem_spinlock; -} old_sem_t; - -/* Maximum value the semaphore can have. */ -#define SEM_VALUE_MAX ((int) ((~0u) >> 1)) - -static inline int sem_compare_and_swap(old_sem_t *sem, long oldval, long newval) -{ - return compare_and_swap(&sem->sem_status, oldval, newval, &sem->sem_spinlock); -} - -/* The state of a semaphore is represented by a long int encoding - either the semaphore count if >= 0 and no thread is waiting on it, - or the head of the list of threads waiting for the semaphore. - To distinguish the two cases, we encode the semaphore count N - as 2N+1, so that it has the lowest bit set. - - A sequence of sem_wait operations on a semaphore initialized to N - result in the following successive states: - 2N+1, 2N-1, ..., 3, 1, &first_waiting_thread, &second_waiting_thread, ... -*/ - -static void sem_restart_list(pthread_descr waiting); - -int __old_sem_init(old_sem_t *sem, int pshared, unsigned int value) -{ - if (value > SEM_VALUE_MAX) { - errno = EINVAL; - return -1; - } - if (pshared) { - errno = ENOSYS; - return -1; - } - sem->sem_spinlock = 0; - sem->sem_status = ((long)value << 1) + 1; - return 0; -} - -/* Function called by pthread_cancel to remove the thread from - waiting inside __old_sem_wait. Here we simply unconditionally - indicate that the thread is to be woken, by returning 1. */ - -static int old_sem_extricate_func(void *obj, pthread_descr th) -{ - return 1; -} - -int __old_sem_wait(old_sem_t * sem) -{ - long oldstatus, newstatus; - volatile pthread_descr self = thread_self(); - pthread_descr * th; - pthread_extricate_if extr; - - /* Set up extrication interface */ - extr.pu_object = 0; - extr.pu_extricate_func = old_sem_extricate_func; - - while (1) { - /* Register extrication interface */ - __pthread_set_own_extricate_if(self, &extr); - do { - oldstatus = sem->sem_status; - if ((oldstatus & 1) && (oldstatus != 1)) - newstatus = oldstatus - 2; - else { - newstatus = (long) self; - self->p_nextwaiting = (pthread_descr) oldstatus; - } - } - while (! sem_compare_and_swap(sem, oldstatus, newstatus)); - if (newstatus & 1) { - /* We got the semaphore. */ - __pthread_set_own_extricate_if(self, 0); - return 0; - } - /* Wait for sem_post or cancellation */ - suspend(self); - __pthread_set_own_extricate_if(self, 0); - - /* This is a cancellation point */ - if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) { - /* Remove ourselves from the waiting list if we're still on it */ - /* First check if we're at the head of the list. */ - do { - oldstatus = sem->sem_status; - if (oldstatus != (long) self) break; - newstatus = (long) self->p_nextwaiting; - } - while (! sem_compare_and_swap(sem, oldstatus, newstatus)); - /* Now, check if we're somewhere in the list. - There's a race condition with sem_post here, but it does not matter: - the net result is that at the time pthread_exit is called, - self is no longer reachable from sem->sem_status. */ - if (oldstatus != (long) self && (oldstatus & 1) == 0) { - for (th = &(((pthread_descr) oldstatus)->p_nextwaiting); - *th != NULL && *th != (pthread_descr) 1; - th = &((*th)->p_nextwaiting)) { - if (*th == self) { - *th = self->p_nextwaiting; - break; - } - } - } - pthread_exit(PTHREAD_CANCELED); - } - } -} - -int __old_sem_trywait(old_sem_t * sem) -{ - long oldstatus, newstatus; - - do { - oldstatus = sem->sem_status; - if ((oldstatus & 1) == 0 || (oldstatus == 1)) { - errno = EAGAIN; - return -1; - } - newstatus = oldstatus - 2; - } - while (! sem_compare_and_swap(sem, oldstatus, newstatus)); - return 0; -} - -int __old_sem_post(old_sem_t * sem) -{ - long oldstatus, newstatus; - - do { - oldstatus = sem->sem_status; - if ((oldstatus & 1) == 0) - newstatus = 3; - else { - if (oldstatus >= SEM_VALUE_MAX) { - /* Overflow */ - errno = ERANGE; - return -1; - } - newstatus = oldstatus + 2; - } - } - while (! sem_compare_and_swap(sem, oldstatus, newstatus)); - if ((oldstatus & 1) == 0) - sem_restart_list((pthread_descr) oldstatus); - return 0; -} - -int __old_sem_getvalue(old_sem_t * sem, int * sval) -{ - long status = sem->sem_status; - if (status & 1) - *sval = (int)((unsigned long) status >> 1); - else - *sval = 0; - return 0; -} - -int __old_sem_destroy(old_sem_t * sem) -{ - if ((sem->sem_status & 1) == 0) { - errno = EBUSY; - return -1; - } - return 0; -} - -/* Auxiliary function for restarting all threads on a waiting list, - in priority order. */ - -static void sem_restart_list(pthread_descr waiting) -{ - pthread_descr th, towake, *p; - - /* Sort list of waiting threads by decreasing priority (insertion sort) */ - towake = NULL; - while (waiting != (pthread_descr) 1) { - th = waiting; - waiting = waiting->p_nextwaiting; - p = &towake; - while (*p != NULL && th->p_priority < (*p)->p_priority) - p = &((*p)->p_nextwaiting); - th->p_nextwaiting = *p; - *p = th; - } - /* Wake up threads in priority order */ - while (towake != NULL) { - th = towake; - towake = towake->p_nextwaiting; - th->p_nextwaiting = NULL; - restart(th); - } -} - -#if defined __PIC__ && defined DO_VERSIONING -symbol_version (__old_sem_init, sem_init, GLIBC_2.0); -symbol_version (__old_sem_wait, sem_wait, GLIBC_2.0); -symbol_version (__old_sem_trywait, sem_trywait, GLIBC_2.0); -symbol_version (__old_sem_post, sem_post, GLIBC_2.0); -symbol_version (__old_sem_getvalue, sem_getvalue, GLIBC_2.0); -symbol_version (__old_sem_destroy, sem_destroy, GLIBC_2.0); -#endif - diff --git a/libpthread/linuxthreads/pt-machine.c b/libpthread/linuxthreads/pt-machine.c deleted file mode 100644 index 438008d5d..000000000 --- a/libpthread/linuxthreads/pt-machine.c +++ /dev/null @@ -1,22 +0,0 @@ -/* "Instantiation of machine-dependent pthreads inline functions. - Copyright (C) 1998 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#define PT_EI - -#include diff --git a/libpthread/linuxthreads/ptfork.c b/libpthread/linuxthreads/ptfork.c deleted file mode 100644 index eb544f34b..000000000 --- a/libpthread/linuxthreads/ptfork.c +++ /dev/null @@ -1,126 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* mods for uClibc: removed strong alias and defined funcs properly */ - -/* The "atfork" stuff */ - -#include - -#ifdef __ARCH_HAS_MMU__ - -#include -#include -#include -#include "pthread.h" -#include "internals.h" - -struct handler_list { - void (*handler)(void); - struct handler_list * next; -}; - -static pthread_mutex_t pthread_atfork_lock = PTHREAD_MUTEX_INITIALIZER; -static struct handler_list * pthread_atfork_prepare = NULL; -static struct handler_list * pthread_atfork_parent = NULL; -static struct handler_list * pthread_atfork_child = NULL; - -static void pthread_insert_list(struct handler_list ** list, - void (*handler)(void), - struct handler_list * newlist, - int at_end) -{ - if (handler == NULL) return; - if (at_end) { - while(*list != NULL) list = &((*list)->next); - } - newlist->handler = handler; - newlist->next = *list; - *list = newlist; -} - -struct handler_list_block { - struct handler_list prepare, parent, child; -}; - -int pthread_atfork(void (*prepare)(void), - void (*parent)(void), - void (*child)(void)) -{ - struct handler_list_block * block = - (struct handler_list_block *) malloc(sizeof(struct handler_list_block)); - if (block == NULL) return ENOMEM; - pthread_mutex_lock(&pthread_atfork_lock); - /* "prepare" handlers are called in LIFO */ - pthread_insert_list(&pthread_atfork_prepare, prepare, &block->prepare, 0); - /* "parent" handlers are called in FIFO */ - pthread_insert_list(&pthread_atfork_parent, parent, &block->parent, 1); - /* "child" handlers are called in FIFO */ - pthread_insert_list(&pthread_atfork_child, child, &block->child, 1); - pthread_mutex_unlock(&pthread_atfork_lock); - return 0; -} -//strong_alias (__pthread_atfork, pthread_atfork) - -static inline void pthread_call_handlers(struct handler_list * list) -{ - for (/*nothing*/; list != NULL; list = list->next) (list->handler)(); -} - -extern int __libc_fork(void); - -pid_t __fork(void) -{ - pid_t pid; - struct handler_list * prepare, * child, * parent; - - pthread_mutex_lock(&pthread_atfork_lock); - prepare = pthread_atfork_prepare; - child = pthread_atfork_child; - parent = pthread_atfork_parent; - pthread_mutex_unlock(&pthread_atfork_lock); - pthread_call_handlers(prepare); - pid = __libc_fork(); - if (pid == 0) { - __pthread_reset_main_thread(); - __fresetlockfiles(); - pthread_call_handlers(child); - } else { - pthread_call_handlers(parent); - } - return pid; -} -weak_alias (__fork, fork); - -pid_t __vfork(void) -{ - return __fork(); -} -weak_alias (__vfork, vfork); - -#else - -/* We can't support pthread_atfork without MMU, since we don't have - fork(), and we can't offer the correct semantics for vfork(). */ -int pthread_atfork(void (*prepare)(void), - void (*parent)(void), - void (*child)(void)) -{ - /* ENOMEM is probably pushing it a little bit. - Take it as `no *virtual* memory' :-) */ - errno = ENOMEM; - return -1; -} - -#endif diff --git a/libpthread/linuxthreads/pthread.c b/libpthread/linuxthreads/pthread.c deleted file mode 100644 index fed3d8c72..000000000 --- a/libpthread/linuxthreads/pthread.c +++ /dev/null @@ -1,1044 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Thread creation, initialization, and basic low-level routines */ - -#define __FORCE_GLIBC -#include -#define __USE_GNU -#include -#include /* for h_errno */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "restart.h" -#include "debug.h" /* added to linuxthreads -StS */ - - -/* Mods for uClibc: Some includes */ -#include -#include -#include - -/* mods for uClibc: getpwd and getpagesize are the syscalls */ -#define __getpid getpid -#define __getpagesize getpagesize -/* mods for uClibc: __libc_sigaction is not in any standard headers */ -extern int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact); - - -/* These variables are used by the setup code. */ -extern int _errno; -extern int _h_errno; - - -/* Descriptor of the initial thread */ - -struct _pthread_descr_struct __pthread_initial_thread = { - &__pthread_initial_thread, /* pthread_descr p_nextlive */ - &__pthread_initial_thread, /* pthread_descr p_prevlive */ - NULL, /* pthread_descr p_nextwaiting */ - NULL, /* pthread_descr p_nextlock */ - PTHREAD_THREADS_MAX, /* pthread_t p_tid */ - 0, /* int p_pid */ - 0, /* int p_priority */ - &__pthread_handles[0].h_lock, /* struct _pthread_fastlock * p_lock */ - 0, /* int p_signal */ - NULL, /* sigjmp_buf * p_signal_buf */ - NULL, /* sigjmp_buf * p_cancel_buf */ - 0, /* char p_terminated */ - 0, /* char p_detached */ - 0, /* char p_exited */ - NULL, /* void * p_retval */ - 0, /* int p_retval */ - NULL, /* pthread_descr p_joining */ - NULL, /* struct _pthread_cleanup_buffer * p_cleanup */ - 0, /* char p_cancelstate */ - 0, /* char p_canceltype */ - 0, /* char p_canceled */ - &_errno, /* int *p_errnop */ - 0, /* int p_errno */ - &_h_errno, /* int *p_h_errnop */ - 0, /* int p_h_errno */ - NULL, /* char * p_in_sighandler */ - 0, /* char p_sigwaiting */ - PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */ - {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */ - {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */ - 0, /* int p_userstack */ - NULL, /* void * p_guardaddr */ - 0, /* size_t p_guardsize */ - &__pthread_initial_thread, /* pthread_descr p_self */ - 0, /* Always index 0 */ - 0, /* int p_report_events */ - {{{0, }}, 0, NULL}, /* td_eventbuf_t p_eventbuf */ - __ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */ - 0, /* char p_woken_by_cancel */ - 0, /* char p_condvar_avail */ - 0, /* char p_sem_avail */ - NULL, /* struct pthread_extricate_if *p_extricate */ - NULL, /* pthread_readlock_info *p_readlock_list; */ - NULL, /* pthread_readlock_info *p_readlock_free; */ - 0 /* int p_untracked_readlock_count; */ -#ifdef __UCLIBC_HAS_XLOCALE__ - , - &__global_locale_data, /* __locale_t locale; */ -#endif /* __UCLIBC_HAS_XLOCALE__ */ -}; - -/* Descriptor of the manager thread; none of this is used but the error - variables, the p_pid and p_priority fields, - and the address for identification. */ -#define manager_thread (&__pthread_manager_thread) -struct _pthread_descr_struct __pthread_manager_thread = { - NULL, /* pthread_descr p_nextlive */ - NULL, /* pthread_descr p_prevlive */ - NULL, /* pthread_descr p_nextwaiting */ - NULL, /* pthread_descr p_nextlock */ - 0, /* int p_tid */ - 0, /* int p_pid */ - 0, /* int p_priority */ - &__pthread_handles[1].h_lock, /* struct _pthread_fastlock * p_lock */ - 0, /* int p_signal */ - NULL, /* sigjmp_buf * p_signal_buf */ - NULL, /* sigjmp_buf * p_cancel_buf */ - 0, /* char p_terminated */ - 0, /* char p_detached */ - 0, /* char p_exited */ - NULL, /* void * p_retval */ - 0, /* int p_retval */ - NULL, /* pthread_descr p_joining */ - NULL, /* struct _pthread_cleanup_buffer * p_cleanup */ - 0, /* char p_cancelstate */ - 0, /* char p_canceltype */ - 0, /* char p_canceled */ - &__pthread_manager_thread.p_errno, /* int *p_errnop */ - 0, /* int p_errno */ - NULL, /* int *p_h_errnop */ - 0, /* int p_h_errno */ - NULL, /* char * p_in_sighandler */ - 0, /* char p_sigwaiting */ - PTHREAD_START_ARGS_INITIALIZER, /* struct pthread_start_args p_start_args */ - {NULL}, /* void ** p_specific[PTHREAD_KEY_1STLEVEL_SIZE] */ - {NULL}, /* void * p_libc_specific[_LIBC_TSD_KEY_N] */ - 0, /* int p_userstack */ - NULL, /* void * p_guardaddr */ - 0, /* size_t p_guardsize */ - &__pthread_manager_thread, /* pthread_descr p_self */ - 1, /* Always index 1 */ - 0, /* int p_report_events */ - {{{0, }}, 0, NULL}, /* td_eventbuf_t p_eventbuf */ - __ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */ - 0, /* char p_woken_by_cancel */ - 0, /* char p_condvar_avail */ - 0, /* char p_sem_avail */ - NULL, /* struct pthread_extricate_if *p_extricate */ - NULL, /* pthread_readlock_info *p_readlock_list; */ - NULL, /* pthread_readlock_info *p_readlock_free; */ - 0 /* int p_untracked_readlock_count; */ -#ifdef __UCLIBC_HAS_XLOCALE__ - , - &__global_locale_data, /* __locale_t locale; */ -#endif /* __UCLIBC_HAS_XLOCALE__ */ -}; - -/* Pointer to the main thread (the father of the thread manager thread) */ -/* Originally, this is the initial thread, but this changes after fork() */ - -pthread_descr __pthread_main_thread = &__pthread_initial_thread; - -/* Limit between the stack of the initial thread (above) and the - stacks of other threads (below). Aligned on a STACK_SIZE boundary. */ - -char *__pthread_initial_thread_bos = NULL; - -/* For non-MMU systems also remember to stack top of the initial thread. - * This is adapted when other stacks are malloc'ed since we don't know - * the bounds a-priori. -StS */ - -#ifndef __ARCH_HAS_MMU__ -char *__pthread_initial_thread_tos = NULL; -#endif /* __ARCH_HAS_MMU__ */ - -/* File descriptor for sending requests to the thread manager. */ -/* Initially -1, meaning that the thread manager is not running. */ - -int __pthread_manager_request = -1; - -/* Other end of the pipe for sending requests to the thread manager. */ - -int __pthread_manager_reader; - -/* Limits of the thread manager stack */ - -char *__pthread_manager_thread_bos = NULL; -char *__pthread_manager_thread_tos = NULL; - -/* For process-wide exit() */ - -int __pthread_exit_requested = 0; -int __pthread_exit_code = 0; - -/* Communicate relevant LinuxThreads constants to gdb */ - -const int __pthread_threads_max = PTHREAD_THREADS_MAX; -const int __pthread_sizeof_handle = sizeof(struct pthread_handle_struct); -const int __pthread_offsetof_descr = offsetof(struct pthread_handle_struct, h_descr); -const int __pthread_offsetof_pid = offsetof(struct _pthread_descr_struct, - p_pid); -const int __linuxthreads_pthread_sizeof_descr - = sizeof(struct _pthread_descr_struct); - -const int __linuxthreads_initial_report_events; - -const char __linuxthreads_version[] = VERSION; - -/* Forward declarations */ -static void pthread_onexit_process(int retcode, void *arg); -static void pthread_handle_sigcancel(int sig); -static void pthread_handle_sigrestart(int sig); -static void pthread_handle_sigdebug(int sig); -int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime); - -/* Signal numbers used for the communication. - In these variables we keep track of the used variables. If the - platform does not support any real-time signals we will define the - values to some unreasonable value which will signal failing of all - the functions below. */ -#ifndef __NR_rt_sigaction -static int current_rtmin = -1; -static int current_rtmax = -1; -int __pthread_sig_restart = SIGUSR1; -int __pthread_sig_cancel = SIGUSR2; -int __pthread_sig_debug; -#else - -#if __SIGRTMAX - __SIGRTMIN >= 3 -static int current_rtmin = __SIGRTMIN + 3; -static int current_rtmax = __SIGRTMAX; -int __pthread_sig_restart = __SIGRTMIN; -int __pthread_sig_cancel = __SIGRTMIN + 1; -int __pthread_sig_debug = __SIGRTMIN + 2; -void (*__pthread_restart)(pthread_descr) = __pthread_restart_new; -void (*__pthread_suspend)(pthread_descr) = __pthread_wait_for_restart_signal; -int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_new; -#else -static int current_rtmin = __SIGRTMIN; -static int current_rtmax = __SIGRTMAX; -int __pthread_sig_restart = SIGUSR1; -int __pthread_sig_cancel = SIGUSR2; -int __pthread_sig_debug; -void (*__pthread_restart)(pthread_descr) = __pthread_restart_old; -void (*__pthread_suspend)(pthread_descr) = __pthread_suspend_old; -int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *) = __pthread_timedsuspend_old; - -#endif - -/* Return number of available real-time signal with highest priority. */ -int __libc_current_sigrtmin (void) -{ - return current_rtmin; -} - -/* Return number of available real-time signal with lowest priority. */ -int __libc_current_sigrtmax (void) -{ - return current_rtmax; -} - -/* Allocate real-time signal with highest/lowest available - priority. Please note that we don't use a lock since we assume - this function to be called at program start. */ -int __libc_allocate_rtsig (int high) -{ - if (current_rtmin == -1 || current_rtmin > current_rtmax) - /* We don't have anymore signal available. */ - return -1; - return high ? current_rtmin++ : current_rtmax--; -} -#endif - -/* Initialize the pthread library. - Initialization is split in two functions: - - a constructor function that blocks the __pthread_sig_restart signal - (must do this very early, since the program could capture the signal - mask with e.g. sigsetjmp before creating the first thread); - - a regular function called from pthread_create when needed. */ - -static void pthread_initialize(void) __attribute__((constructor)); - - /* Do some minimal initialization which has to be done during the - startup of the C library. */ -void __pthread_initialize_minimal(void) -{ - /* If we have special thread_self processing, initialize - * that for the main thread now. */ -#ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(&__pthread_initial_thread, 0); -#endif -} - - -static void pthread_initialize(void) -{ - struct sigaction sa; - sigset_t mask; - struct rlimit limit; - int max_stack; - - /* If already done (e.g. by a constructor called earlier!), bail out */ - if (__pthread_initial_thread_bos != NULL) return; -#ifdef TEST_FOR_COMPARE_AND_SWAP - /* Test if compare-and-swap is available */ - __pthread_has_cas = compare_and_swap_is_available(); -#endif - /* For the initial stack, reserve at least STACK_SIZE bytes of stack - below the current stack address, and align that on a - STACK_SIZE boundary. */ - __pthread_initial_thread_bos = - (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1)); - /* Update the descriptor for the initial thread. */ - __pthread_initial_thread.p_pid = __getpid(); - /* If we have special thread_self processing, initialize that for the - main thread now. */ -#ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(&__pthread_initial_thread, 0); -#endif - /* The errno/h_errno variable of the main thread are the global ones. */ - __pthread_initial_thread.p_errnop = &_errno; - __pthread_initial_thread.p_h_errnop = &_h_errno; - -#ifdef __UCLIBC_HAS_XLOCALE__ - /* The locale of the main thread is the current locale in use. */ - __pthread_initial_thread.locale = __curlocale_var; -#endif /* __UCLIBC_HAS_XLOCALE__ */ - - { /* uClibc-specific stdio initialization for threads. */ - FILE *fp; - - _stdio_user_locking = 0; /* 2 if threading not initialized */ - for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) { - if (fp->__user_locking != 1) { - fp->__user_locking = 0; - } - } - } - - /* Play with the stack size limit to make sure that no stack ever grows - beyond STACK_SIZE minus two pages (one page for the thread descriptor - immediately beyond, and one page to act as a guard page). */ - -#ifdef __ARCH_HAS_MMU__ - /* We cannot allocate a huge chunk of memory to mmap all thread stacks later - * on a non-MMU system. Thus, we don't need the rlimit either. -StS */ - getrlimit(RLIMIT_STACK, &limit); - max_stack = STACK_SIZE - 2 * __getpagesize(); - if (limit.rlim_cur > max_stack) { - limit.rlim_cur = max_stack; - setrlimit(RLIMIT_STACK, &limit); - } -#else - /* For non-MMU assume __pthread_initial_thread_tos at upper page boundary, and - * __pthread_initial_thread_bos at address 0. These bounds are refined as we - * malloc other stack frames such that they don't overlap. -StS - */ - __pthread_initial_thread_tos = - (char *)(((long)CURRENT_STACK_FRAME + __getpagesize()) & ~(__getpagesize() - 1)); - __pthread_initial_thread_bos = (char *) 1; /* set it non-zero so we know we have been here */ - PDEBUG("initial thread stack bounds: bos=%p, tos=%p\n", - __pthread_initial_thread_bos, __pthread_initial_thread_tos); -#endif /* __ARCH_HAS_MMU__ */ - - /* Setup signal handlers for the initial thread. - Since signal handlers are shared between threads, these settings - will be inherited by all other threads. */ - sa.sa_handler = pthread_handle_sigrestart; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - __libc_sigaction(__pthread_sig_restart, &sa, NULL); - sa.sa_handler = pthread_handle_sigcancel; - sigaddset(&sa.sa_mask, __pthread_sig_restart); - // sa.sa_flags = 0; - __libc_sigaction(__pthread_sig_cancel, &sa, NULL); - if (__pthread_sig_debug > 0) { - sa.sa_handler = pthread_handle_sigdebug; - sigemptyset(&sa.sa_mask); - // sa.sa_flags = 0; - __libc_sigaction(__pthread_sig_debug, &sa, NULL); - } - /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */ - sigemptyset(&mask); - sigaddset(&mask, __pthread_sig_restart); - sigprocmask(SIG_BLOCK, &mask, NULL); - /* And unblock __pthread_sig_cancel if it has been blocked. */ - sigdelset(&mask, __pthread_sig_restart); - sigaddset(&mask, __pthread_sig_cancel); - sigprocmask(SIG_UNBLOCK, &mask, NULL); - /* Register an exit function to kill all other threads. */ - /* Do it early so that user-registered atexit functions are called - before pthread_onexit_process. */ - on_exit(pthread_onexit_process, NULL); -} - -void __pthread_initialize(void) -{ - pthread_initialize(); -} - -int __pthread_initialize_manager(void) -{ - int manager_pipe[2]; - int pid; - int report_events; - struct pthread_request request; - - /* If basic initialization not done yet (e.g. we're called from a - constructor run before our constructor), do it now */ - if (__pthread_initial_thread_bos == NULL) pthread_initialize(); - /* Setup stack for thread manager */ - __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE); - if (__pthread_manager_thread_bos == NULL) return -1; - __pthread_manager_thread_tos = - __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE; - - /* On non-MMU systems we make sure that the initial thread bounds don't overlap - * with the manager stack frame */ - NOMMU_INITIAL_THREAD_BOUNDS(__pthread_manager_thread_tos,__pthread_manager_thread_bos); - PDEBUG("manager stack: size=%d, bos=%p, tos=%p\n", THREAD_MANAGER_STACK_SIZE, - __pthread_manager_thread_bos, __pthread_manager_thread_tos); -#if 0 - PDEBUG("initial stack: estimate bos=%p, tos=%p\n", - __pthread_initial_thread_bos, __pthread_initial_thread_tos); -#endif - - /* Setup pipe to communicate with thread manager */ - if (pipe(manager_pipe) == -1) { - free(__pthread_manager_thread_bos); - return -1; - } - /* Start the thread manager */ - pid = 0; -#ifdef USE_TLS - if (__linuxthreads_initial_report_events != 0) - THREAD_SETMEM (((pthread_descr) NULL), p_report_events, - __linuxthreads_initial_report_events); - report_events = THREAD_GETMEM (((pthread_descr) NULL), p_report_events); -#else - if (__linuxthreads_initial_report_events != 0) - __pthread_initial_thread.p_report_events - = __linuxthreads_initial_report_events; - report_events = __pthread_initial_thread.p_report_events; -#endif - if (__builtin_expect (report_events, 0)) - { - /* It's a bit more complicated. We have to report the creation of - the manager thread. */ - int idx = __td_eventword (TD_CREATE); - uint32_t mask = __td_eventmask (TD_CREATE); - - if ((mask & (__pthread_threads_events.event_bits[idx] - | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx])) - != 0) - { - - __pthread_lock(__pthread_manager_thread.p_lock, NULL); - - pid = clone(__pthread_manager_event, - (void **) __pthread_manager_thread_tos, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(long)manager_pipe[0]); - - if (pid != -1) - { - /* Now fill in the information about the new thread in - the newly created thread's data structure. We cannot let - the new thread do this since we don't know whether it was - already scheduled when we send the event. */ - __pthread_manager_thread.p_eventbuf.eventdata = - &__pthread_manager_thread; - __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE; - __pthread_last_event = &__pthread_manager_thread; - __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; - __pthread_manager_thread.p_pid = pid; - - /* Now call the function which signals the event. */ - __linuxthreads_create_event (); - } - /* Now restart the thread. */ - __pthread_unlock(__pthread_manager_thread.p_lock); - } - } - - if (pid == 0) { - pid = clone(__pthread_manager, (void **) __pthread_manager_thread_tos, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, - (void *)(long)manager_pipe[0]); - } - if (pid == -1) { - free(__pthread_manager_thread_bos); - __libc_close(manager_pipe[0]); - __libc_close(manager_pipe[1]); - return -1; - } - __pthread_manager_request = manager_pipe[1]; /* writing end */ - __pthread_manager_reader = manager_pipe[0]; /* reading end */ - __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1; - __pthread_manager_thread.p_pid = pid; - - /* Make gdb aware of new thread manager */ - if (__pthread_threads_debug && __pthread_sig_debug > 0) - { - raise(__pthread_sig_debug); - /* We suspend ourself and gdb will wake us up when it is - ready to handle us. */ - __pthread_wait_for_restart_signal(thread_self()); - } - /* Synchronize debugging of the thread manager */ - PDEBUG("send REQ_DEBUG to manager thread\n"); - request.req_kind = REQ_DEBUG; - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *) &request, sizeof(request))); - return 0; -} - -/* Thread creation */ - -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, - void * (*start_routine)(void *), void *arg) -{ - pthread_descr self = thread_self(); - struct pthread_request request; - if (__pthread_manager_request < 0) { - if (__pthread_initialize_manager() < 0) return EAGAIN; - } - request.req_thread = self; - request.req_kind = REQ_CREATE; - request.req_args.create.attr = attr; - request.req_args.create.fn = start_routine; - request.req_args.create.arg = arg; - sigprocmask(SIG_SETMASK, (const sigset_t *) NULL, - &request.req_args.create.mask); - PDEBUG("write REQ_CREATE to manager thread\n"); - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *) &request, sizeof(request))); - PDEBUG("before suspend(self)\n"); - suspend(self); - PDEBUG("after suspend(self)\n"); - if (THREAD_GETMEM(self, p_retcode) == 0) - *thread = (pthread_t) THREAD_GETMEM(self, p_retval); - return THREAD_GETMEM(self, p_retcode); -} - -/* Simple operations on thread identifiers */ - -pthread_t pthread_self(void) -{ - pthread_descr self = thread_self(); - return THREAD_GETMEM(self, p_tid); -} - -int pthread_equal(pthread_t thread1, pthread_t thread2) -{ - return thread1 == thread2; -} - -/* Helper function for thread_self in the case of user-provided stacks */ - -#ifndef THREAD_SELF - -pthread_descr __pthread_find_self() -{ - char * sp = CURRENT_STACK_FRAME; - pthread_handle h; - - /* __pthread_handles[0] is the initial thread, __pthread_handles[1] is - the manager threads handled specially in thread_self(), so start at 2 */ - h = __pthread_handles + 2; - while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) h++; - -#ifdef DEBUG_PT - if (h->h_descr == NULL) { - printf("*** %s ERROR descriptor is NULL!!!!! ***\n\n", __FUNCTION__); - _exit(1); - } -#endif - - return h->h_descr; -} -#else - -static pthread_descr thread_self_stack(void) -{ - char *sp = CURRENT_STACK_FRAME; - pthread_handle h; - - if (sp >= __pthread_manager_thread_bos && sp < __pthread_manager_thread_tos) - return manager_thread; - h = __pthread_handles + 2; -# ifdef USE_TLS - while (h->h_descr == NULL - || ! (sp <= (char *) h->h_descr->p_stackaddr && sp >= h->h_bottom)) - h++; -# else - while (! (sp <= (char *) h->h_descr && sp >= h->h_bottom)) - h++; -# endif - return h->h_descr; -} - -#endif - -/* Thread scheduling */ - -int pthread_setschedparam(pthread_t thread, int policy, - const struct sched_param *param) -{ - pthread_handle handle = thread_handle(thread); - pthread_descr th; - - __pthread_lock(&handle->h_lock, NULL); - if (invalid_handle(handle, thread)) { - __pthread_unlock(&handle->h_lock); - return ESRCH; - } - th = handle->h_descr; - if (sched_setscheduler(th->p_pid, policy, param) == -1) { - __pthread_unlock(&handle->h_lock); - return errno; - } - th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority; - __pthread_unlock(&handle->h_lock); - if (__pthread_manager_request >= 0) - __pthread_manager_adjust_prio(th->p_priority); - return 0; -} - -int pthread_getschedparam(pthread_t thread, int *policy, - struct sched_param *param) -{ - pthread_handle handle = thread_handle(thread); - int pid, pol; - - __pthread_lock(&handle->h_lock, NULL); - if (invalid_handle(handle, thread)) { - __pthread_unlock(&handle->h_lock); - return ESRCH; - } - pid = handle->h_descr->p_pid; - __pthread_unlock(&handle->h_lock); - pol = sched_getscheduler(pid); - if (pol == -1) return errno; - if (sched_getparam(pid, param) == -1) return errno; - *policy = pol; - return 0; -} - -/* Process-wide exit() request */ - -static void pthread_onexit_process(int retcode, void *arg) -{ - struct pthread_request request; - pthread_descr self = thread_self(); - - if (__pthread_manager_request >= 0) { - request.req_thread = self; - request.req_kind = REQ_PROCESS_EXIT; - request.req_args.exit.code = retcode; - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *) &request, sizeof(request))); - suspend(self); - /* Main thread should accumulate times for thread manager and its - children, so that timings for main thread account for all threads. */ - if (self == __pthread_main_thread) { - waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); - /* Since all threads have been asynchronously terminated - * (possibly holding locks), free cannot be used any more. */ - __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; - } - } -} - -/* The handler for the RESTART signal just records the signal received - in the thread descriptor, and optionally performs a siglongjmp - (for pthread_cond_timedwait). */ - -static void pthread_handle_sigrestart(int sig) -{ - pthread_descr self = thread_self(); - THREAD_SETMEM(self, p_signal, sig); - if (THREAD_GETMEM(self, p_signal_jmp) != NULL) - siglongjmp(*THREAD_GETMEM(self, p_signal_jmp), 1); -} - -/* The handler for the CANCEL signal checks for cancellation - (in asynchronous mode), for process-wide exit and exec requests. - For the thread manager thread, redirect the signal to - __pthread_manager_sighandler. */ - -static void pthread_handle_sigcancel(int sig) -{ - pthread_descr self = thread_self(); - sigjmp_buf * jmpbuf; - - - if (self == &__pthread_manager_thread) - { -#ifdef THREAD_SELF - /* A new thread might get a cancel signal before it is fully - initialized, so that the thread register might still point to the - manager thread. Double check that this is really the manager - thread. */ - pthread_descr real_self = thread_self_stack(); - if (real_self == &__pthread_manager_thread) - { - __pthread_manager_sighandler(sig); - return; - } - /* Oops, thread_self() isn't working yet.. */ - self = real_self; -# ifdef INIT_THREAD_SELF - INIT_THREAD_SELF(self, self->p_nr); -# endif -#else - __pthread_manager_sighandler(sig); - return; -#endif - } - if (__builtin_expect (__pthread_exit_requested, 0)) { - /* Main thread should accumulate times for thread manager and its - children, so that timings for main thread account for all threads. */ - if (self == __pthread_main_thread) { -#ifdef USE_TLS - waitpid(__pthread_manager_thread->p_pid, NULL, __WCLONE); -#else - waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE); -#endif - } - _exit(__pthread_exit_code); - } - if (__builtin_expect (THREAD_GETMEM(self, p_canceled), 0) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { - if (THREAD_GETMEM(self, p_canceltype) == PTHREAD_CANCEL_ASYNCHRONOUS) - pthread_exit(PTHREAD_CANCELED); - jmpbuf = THREAD_GETMEM(self, p_cancel_jmp); - if (jmpbuf != NULL) { - THREAD_SETMEM(self, p_cancel_jmp, NULL); - siglongjmp(*jmpbuf, 1); - } - } -} - -/* Handler for the DEBUG signal. - The debugging strategy is as follows: - On reception of a REQ_DEBUG request (sent by new threads created to - the thread manager under debugging mode), the thread manager throws - __pthread_sig_debug to itself. The debugger (if active) intercepts - this signal, takes into account new threads and continue execution - of the thread manager by propagating the signal because it doesn't - know what it is specifically done for. In the current implementation, - the thread manager simply discards it. */ - -static void pthread_handle_sigdebug(int sig) -{ - /* Nothing */ -} - -/* Reset the state of the thread machinery after a fork(). - Close the pipe used for requests and set the main thread to the forked - thread. - Notice that we can't free the stack segments, as the forked thread - may hold pointers into them. */ - -void __pthread_reset_main_thread() -{ - pthread_descr self = thread_self(); - - if (__pthread_manager_request != -1) { - /* Free the thread manager stack */ - free(__pthread_manager_thread_bos); - __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; - /* Close the two ends of the pipe */ - __libc_close(__pthread_manager_request); - __libc_close(__pthread_manager_reader); - __pthread_manager_request = __pthread_manager_reader = -1; - } - - /* Update the pid of the main thread */ - THREAD_SETMEM(self, p_pid, __getpid()); - /* Make the forked thread the main thread */ - __pthread_main_thread = self; - THREAD_SETMEM(self, p_nextlive, self); - THREAD_SETMEM(self, p_prevlive, self); - /* Now this thread modifies the global variables. */ - THREAD_SETMEM(self, p_errnop, &_errno); - THREAD_SETMEM(self, p_h_errnop, &_h_errno); -} - -/* Process-wide exec() request */ - -void __pthread_kill_other_threads_np(void) -{ - struct sigaction sa; - /* Terminate all other threads and thread manager */ - pthread_onexit_process(0, NULL); - /* Make current thread the main thread in case the calling thread - changes its mind, does not exec(), and creates new threads instead. */ - __pthread_reset_main_thread(); - /* Reset the signal handlers behaviour for the signals the - implementation uses since this would be passed to the new - process. */ - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = SIG_DFL; - __libc_sigaction(__pthread_sig_restart, &sa, NULL); - __libc_sigaction(__pthread_sig_cancel, &sa, NULL); - if (__pthread_sig_debug > 0) - __libc_sigaction(__pthread_sig_debug, &sa, NULL); -} -weak_alias (__pthread_kill_other_threads_np, pthread_kill_other_threads_np) - -/* Concurrency symbol level. */ -static int current_level; - -int __pthread_setconcurrency(int level) -{ - /* We don't do anything unless we have found a useful interpretation. */ - current_level = level; - return 0; -} -weak_alias (__pthread_setconcurrency, pthread_setconcurrency) - -int __pthread_getconcurrency(void) -{ - return current_level; -} -weak_alias (__pthread_getconcurrency, pthread_getconcurrency) - - -/* Primitives for controlling thread execution */ - -void __pthread_wait_for_restart_signal(pthread_descr self) -{ - sigset_t mask; - - sigprocmask(SIG_SETMASK, NULL, &mask); /* Get current signal mask */ - sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */ - THREAD_SETMEM(self, p_signal, 0); - do { - sigsuspend(&mask); /* Wait for signal */ - } while (THREAD_GETMEM(self, p_signal) !=__pthread_sig_restart); - - READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */ -} - -#ifndef __NR_rt_sigaction -/* The _old variants are for 2.0 and early 2.1 kernels which don't have RT - signals. - On these kernels, we use SIGUSR1 and SIGUSR2 for restart and cancellation. - Since the restart signal does not queue, we use an atomic counter to create - queuing semantics. This is needed to resolve a rare race condition in - pthread_cond_timedwait_relative. */ - -void __pthread_restart_old(pthread_descr th) -{ - if (atomic_increment(&th->p_resume_count) == -1) - kill(th->p_pid, __pthread_sig_restart); -} - -void __pthread_suspend_old(pthread_descr self) -{ - if (atomic_decrement(&self->p_resume_count) <= 0) - __pthread_wait_for_restart_signal(self); -} - -int -__pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime) -{ - sigset_t unblock, initial_mask; - int was_signalled = 0; - sigjmp_buf jmpbuf; - - if (atomic_decrement(&self->p_resume_count) == 0) { - /* Set up a longjmp handler for the restart signal, unblock - the signal and sleep. */ - - if (sigsetjmp(jmpbuf, 1) == 0) { - THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); - THREAD_SETMEM(self, p_signal, 0); - /* Unblock the restart signal */ - sigemptyset(&unblock); - sigaddset(&unblock, __pthread_sig_restart); - sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); - - while (1) { - struct timeval now; - struct timespec reltime; - - /* Compute a time offset relative to now. */ - __gettimeofday (&now, NULL); - reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; - reltime.tv_sec = abstime->tv_sec - now.tv_sec; - if (reltime.tv_nsec < 0) { - reltime.tv_nsec += 1000000000; - reltime.tv_sec -= 1; - } - - /* Sleep for the required duration. If woken by a signal, - resume waiting as required by Single Unix Specification. */ - if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) - break; - } - - /* Block the restart signal again */ - sigprocmask(SIG_SETMASK, &initial_mask, NULL); - was_signalled = 0; - } else { - was_signalled = 1; - } - THREAD_SETMEM(self, p_signal_jmp, NULL); - } - - /* Now was_signalled is true if we exited the above code - due to the delivery of a restart signal. In that case, - we know we have been dequeued and resumed and that the - resume count is balanced. Otherwise, there are some - cases to consider. First, try to bump up the resume count - back to zero. If it goes to 1, it means restart() was - invoked on this thread. The signal must be consumed - and the count bumped down and everything is cool. We - can return a 1 to the caller. - Otherwise, no restart was delivered yet, so a potential - race exists; we return a 0 to the caller which must deal - with this race in an appropriate way; for example by - atomically removing the thread from consideration for a - wakeup---if such a thing fails, it means a restart is - being delivered. */ - - if (!was_signalled) { - if (atomic_increment(&self->p_resume_count) != -1) { - __pthread_wait_for_restart_signal(self); - atomic_decrement(&self->p_resume_count); /* should be zero now! */ - /* woke spontaneously and consumed restart signal */ - return 1; - } - /* woke spontaneously but did not consume restart---caller must resolve */ - return 0; - } - /* woken due to restart signal */ - return 1; -} -#endif /* __NR_rt_sigaction */ - - -#ifdef __NR_rt_sigaction -void __pthread_restart_new(pthread_descr th) -{ - /* The barrier is proabably not needed, in which case it still documents - our assumptions. The intent is to commit previous writes to shared - memory so the woken thread will have a consistent view. Complementary - read barriers are present to the suspend functions. */ - WRITE_MEMORY_BARRIER(); - kill(th->p_pid, __pthread_sig_restart); -} - -int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime) -{ - sigset_t unblock, initial_mask; - int was_signalled = 0; - sigjmp_buf jmpbuf; - - if (sigsetjmp(jmpbuf, 1) == 0) { - THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); - THREAD_SETMEM(self, p_signal, 0); - /* Unblock the restart signal */ - sigemptyset(&unblock); - sigaddset(&unblock, __pthread_sig_restart); - sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); - - while (1) { - struct timeval now; - struct timespec reltime; - - /* Compute a time offset relative to now. */ - gettimeofday (&now, NULL); - reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; - reltime.tv_sec = abstime->tv_sec - now.tv_sec; - if (reltime.tv_nsec < 0) { - reltime.tv_nsec += 1000000000; - reltime.tv_sec -= 1; - } - - /* Sleep for the required duration. If woken by a signal, - resume waiting as required by Single Unix Specification. */ - if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) - break; - } - - /* Block the restart signal again */ - sigprocmask(SIG_SETMASK, &initial_mask, NULL); - was_signalled = 0; - } else { - was_signalled = 1; - } - THREAD_SETMEM(self, p_signal_jmp, NULL); - - /* Now was_signalled is true if we exited the above code - due to the delivery of a restart signal. In that case, - everything is cool. We have been removed from whatever - we were waiting on by the other thread, and consumed its signal. - - Otherwise we this thread woke up spontaneously, or due to a signal other - than restart. This is an ambiguous case that must be resolved by - the caller; the thread is still eligible for a restart wakeup - so there is a race. */ - - READ_MEMORY_BARRIER(); /* See comment in __pthread_restart_new */ - return was_signalled; -} -#endif - -/* Debugging aid */ - -#ifdef DEBUG_PT -#include - -void __pthread_message(char * fmt, ...) -{ - char buffer[1024]; - va_list args; - sprintf(buffer, "%05d : ", __getpid()); - va_start(args, fmt); - vsnprintf(buffer + 8, sizeof(buffer) - 8, fmt, args); - va_end(args); - TEMP_FAILURE_RETRY(__libc_write(2, buffer, strlen(buffer))); -} - -#endif - - -#ifndef __PIC__ -/* We need a hook to force the cancelation wrappers to be linked in when - static libpthread is used. */ -extern const int __pthread_provide_wrappers; -static const int *const __pthread_require_wrappers = - &__pthread_provide_wrappers; -#endif diff --git a/libpthread/linuxthreads/pthread.c-OLDEXAMPLE b/libpthread/linuxthreads/pthread.c-OLDEXAMPLE deleted file mode 100644 index 88b163087..000000000 --- a/libpthread/linuxthreads/pthread.c-OLDEXAMPLE +++ /dev/null @@ -1,121 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * A _very_ simple clone based pthread-like implementation - * - * Copyright (C) 2001,2002 by Erik Andersen - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License - * for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - -#define STACKSIZE 8096 - -#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ -#define CLONE_VM 0x00000100 /* set if VM shared between processes */ -#define CLONE_FS 0x00000200 /* set if fs info shared between proces ses */ -#define CLONE_FILES 0x00000400 /* set if open files shared between pro cesses */ -#define CLONE_SIGHAND 0x00000800 /* set if signal handlers shared */ - - - -/* Lame home-grown clone based threading */ -int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutex_attr) -{ - mutex->__m_lock.__spinlock = 1; - return 0; -} - -int pthread_mutex_lock (pthread_mutex_t *mutex) -{ - while (mutex->__m_lock.__spinlock == 0) { - usleep(10000); - } - --(mutex->__m_lock.__spinlock); - return 0; -} - -int pthread_mutex_unlock (pthread_mutex_t *mutex) -{ - ++(mutex->__m_lock.__spinlock); - return 0; -} - -int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - ++(mutex->__m_lock.__spinlock); - while (cond->__c_lock.__spinlock == 0) { - usleep(10000); - } - --(cond->__c_lock.__spinlock); - return 0; -} - -int pthread_cond_signal(pthread_cond_t *cond) -{ - ++(cond->__c_lock.__spinlock); - return 0; -} - -int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) -{ - cond->__c_lock.__spinlock = 1; - return 0; -} - -int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void* (*fn)(void *), void *data) -{ - long retval; - void **newstack; - int (*clonefunc)(void *) = (int (*)(void *))(fn); - - newstack = (void **) malloc(STACKSIZE); - if (!newstack) - return -1; - newstack = (void **) (STACKSIZE + (char *) newstack); - *--newstack = data; - retval = clone(clonefunc, newstack, - CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD, data); - if (retval < 0) { - errno = -retval; - *thread = 0; - retval = -1; - } else { - *thread = retval; - retval = 0; - } - return retval; -} - -int pthread_join (pthread_t thread, void **thread_return) -{ - int retval; - /* Fixme -- wait for thread and get its return value */ - retval = EXIT_SUCCESS; - if (thread_return) - (int)*thread_return = retval; - _exit(retval); -} -link_warning(pthread_join, "pthread_join is a stub and does not behave properly"); - -void pthread_exit (void *retval) -{ - _exit(*(int *)retval); -} diff --git a/libpthread/linuxthreads/ptlongjmp.c b/libpthread/linuxthreads/ptlongjmp.c deleted file mode 100644 index c0ea8223a..000000000 --- a/libpthread/linuxthreads/ptlongjmp.c +++ /dev/null @@ -1,55 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Redefine siglongjmp and longjmp so that they interact correctly - with cleanup handlers */ - -#include -#include "pthread.h" -#include "internals.h" - -/* These functions are not declared anywhere since they shouldn't be - used at another place but here. */ -extern void __libc_siglongjmp (sigjmp_buf env, int val) - __attribute__ ((noreturn)); -extern void __libc_longjmp (sigjmp_buf env, int val) - __attribute__ ((noreturn)); - - -static void pthread_cleanup_upto(__jmp_buf target) -{ - pthread_descr self = thread_self(); - struct _pthread_cleanup_buffer * c; - - for (c = THREAD_GETMEM(self, p_cleanup); - c != NULL && _JMPBUF_UNWINDS(target, c); - c = c->__prev) - c->__routine(c->__arg); - THREAD_SETMEM(self, p_cleanup, c); - if (THREAD_GETMEM(self, p_in_sighandler) - && _JMPBUF_UNWINDS(target, THREAD_GETMEM(self, p_in_sighandler))) - THREAD_SETMEM(self, p_in_sighandler, NULL); -} - -void siglongjmp(sigjmp_buf env, int val) -{ - pthread_cleanup_upto(env->__jmpbuf); - __libc_siglongjmp(env, val); -} - -void longjmp(jmp_buf env, int val) -{ - pthread_cleanup_upto(env->__jmpbuf); - __libc_siglongjmp(env, val); -} diff --git a/libpthread/linuxthreads/queue.h b/libpthread/linuxthreads/queue.h deleted file mode 100644 index 28bd75531..000000000 --- a/libpthread/linuxthreads/queue.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Waiting queues */ - -/* Waiting queues are represented by lists of thread descriptors - linked through their p_nextwaiting field. The lists are kept - sorted by decreasing priority, and then decreasing waiting time. */ - -static inline void enqueue(pthread_descr * q, pthread_descr th) -{ - int prio = th->p_priority; - ASSERT(th->p_nextwaiting == NULL); - for (; *q != NULL; q = &((*q)->p_nextwaiting)) { - if (prio > (*q)->p_priority) { - th->p_nextwaiting = *q; - *q = th; - return; - } - } - *q = th; -} - -static inline pthread_descr dequeue(pthread_descr * q) -{ - pthread_descr th; - th = *q; - if (th != NULL) { - *q = th->p_nextwaiting; - th->p_nextwaiting = NULL; - } - return th; -} - -static inline int remove_from_queue(pthread_descr * q, pthread_descr th) -{ - for (; *q != NULL; q = &((*q)->p_nextwaiting)) { - if (*q == th) { - *q = th->p_nextwaiting; - th->p_nextwaiting = NULL; - return 1; - } - } - return 0; -} - -static inline int queue_is_empty(pthread_descr * q) -{ - return *q == NULL; -} diff --git a/libpthread/linuxthreads/restart.h b/libpthread/linuxthreads/restart.h deleted file mode 100644 index 687d92fae..000000000 --- a/libpthread/linuxthreads/restart.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -#include -#include -#define __ASSUME_REALTIME_SIGNALS defined(__NR_rt_sigaction) - -/* Primitives for controlling thread execution */ - -static inline void restart(pthread_descr th) -{ - /* See pthread.c */ -#if __ASSUME_REALTIME_SIGNALS - __pthread_restart_new(th); -#else - __pthread_restart(th); -#endif -} - -static inline void suspend(pthread_descr self) -{ - /* See pthread.c */ -#if __ASSUME_REALTIME_SIGNALS - __pthread_wait_for_restart_signal(self); -#else - __pthread_suspend(self); -#endif -} - -static inline int timedsuspend(pthread_descr self, - const struct timespec *abstime) -{ - /* See pthread.c */ -#if __ASSUME_REALTIME_SIGNALS - return __pthread_timedsuspend_new(self, abstime); -#else - return __pthread_timedsuspend(self, abstime); -#endif -} diff --git a/libpthread/linuxthreads/rwlock.c b/libpthread/linuxthreads/rwlock.c deleted file mode 100644 index 977fd88af..000000000 --- a/libpthread/linuxthreads/rwlock.c +++ /dev/null @@ -1,486 +0,0 @@ -/* Read-write lock implementation. - Copyright (C) 1998 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Xavier Leroy - and Ulrich Drepper , 1998. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include -#include -#include -#include "internals.h" -#include "queue.h" -#include "spinlock.h" -#include "restart.h" - -/* - * Check whether the calling thread already owns one or more read locks on the - * specified lock. If so, return a pointer to the read lock info structure - * corresponding to that lock. - */ - -static pthread_readlock_info * -rwlock_is_in_list(pthread_descr self, pthread_rwlock_t *rwlock) -{ - pthread_readlock_info *info; - - for (info = self->p_readlock_list; info != NULL; info = info->pr_next) - { - if (info->pr_lock == rwlock) - return info; - } - - return NULL; -} - -/* - * Add a new lock to the thread's list of locks for which it has a read lock. - * A new info node must be allocated for this, which is taken from the thread's - * free list, or by calling malloc. If malloc fails, a null pointer is - * returned. Otherwise the lock info structure is initialized and pushed - * onto the thread's list. - */ - -static pthread_readlock_info * -rwlock_add_to_list(pthread_descr self, pthread_rwlock_t *rwlock) -{ - pthread_readlock_info *info = self->p_readlock_free; - - if (info != NULL) - self->p_readlock_free = info->pr_next; - else - info = malloc(sizeof *info); - - if (info == NULL) - return NULL; - - info->pr_lock_count = 1; - info->pr_lock = rwlock; - info->pr_next = self->p_readlock_list; - self->p_readlock_list = info; - - return info; -} - -/* - * If the thread owns a read lock over the given pthread_rwlock_t, - * and this read lock is tracked in the thread's lock list, - * this function returns a pointer to the info node in that list. - * It also decrements the lock count within that node, and if - * it reaches zero, it removes the node from the list. - * If nothing is found, it returns a null pointer. - */ - -static pthread_readlock_info * -rwlock_remove_from_list(pthread_descr self, pthread_rwlock_t *rwlock) -{ - pthread_readlock_info **pinfo; - - for (pinfo = &self->p_readlock_list; *pinfo != NULL; pinfo = &(*pinfo)->pr_next) - { - if ((*pinfo)->pr_lock == rwlock) - { - pthread_readlock_info *info = *pinfo; - if (--info->pr_lock_count == 0) - *pinfo = info->pr_next; - return info; - } - } - - return NULL; -} - -/* - * This function checks whether the conditions are right to place a read lock. - * It returns 1 if so, otherwise zero. The rwlock's internal lock must be - * locked upon entry. - */ - -static int -rwlock_can_rdlock(pthread_rwlock_t *rwlock, int have_lock_already) -{ - /* Can't readlock; it is write locked. */ - if (rwlock->__rw_writer != NULL) - return 0; - - /* Lock prefers readers; get it. */ - if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP) - return 1; - - /* Lock prefers writers, but none are waiting. */ - if (queue_is_empty(&rwlock->__rw_write_waiting)) - return 1; - - /* Writers are waiting, but this thread already has a read lock */ - if (have_lock_already) - return 1; - - /* Writers are waiting, and this is a new lock */ - return 0; -} - -/* - * This function helps support brain-damaged recursive read locking - * semantics required by Unix 98, while maintaining write priority. - * This basically determines whether this thread already holds a read lock - * already. It returns 1 if so, otherwise it returns 0. - * - * If the thread has any ``untracked read locks'' then it just assumes - * that this lock is among them, just to be safe, and returns 1. - * - * Also, if it finds the thread's lock in the list, it sets the pointer - * referenced by pexisting to refer to the list entry. - * - * If the thread has no untracked locks, and the lock is not found - * in its list, then it is added to the list. If this fails, - * then *pout_of_mem is set to 1. - */ - -static int -rwlock_have_already(pthread_descr *pself, pthread_rwlock_t *rwlock, - pthread_readlock_info **pexisting, int *pout_of_mem) -{ - pthread_readlock_info *existing = NULL; - int out_of_mem = 0, have_lock_already = 0; - pthread_descr self = *pself; - - if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP) - { - if (!self) - self = thread_self(); - - existing = rwlock_is_in_list(self, rwlock); - - if (existing != NULL || self->p_untracked_readlock_count > 0) - have_lock_already = 1; - else - { - existing = rwlock_add_to_list(self, rwlock); - if (existing == NULL) - out_of_mem = 1; - } - } - - *pout_of_mem = out_of_mem; - *pexisting = existing; - *pself = self; - - return have_lock_already; -} - -int -pthread_rwlock_init (pthread_rwlock_t *rwlock, - const pthread_rwlockattr_t *attr) -{ - __pthread_init_lock(&rwlock->__rw_lock); - rwlock->__rw_readers = 0; - rwlock->__rw_writer = NULL; - rwlock->__rw_read_waiting = NULL; - rwlock->__rw_write_waiting = NULL; - - if (attr == NULL) - { - rwlock->__rw_kind = PTHREAD_RWLOCK_DEFAULT_NP; - rwlock->__rw_pshared = PTHREAD_PROCESS_PRIVATE; - } - else - { - rwlock->__rw_kind = attr->__lockkind; - rwlock->__rw_pshared = attr->__pshared; - } - - return 0; -} - - -int -pthread_rwlock_destroy (pthread_rwlock_t *rwlock) -{ - int readers; - _pthread_descr writer; - - __pthread_lock (&rwlock->__rw_lock, NULL); - readers = rwlock->__rw_readers; - writer = rwlock->__rw_writer; - __pthread_unlock (&rwlock->__rw_lock); - - if (readers > 0 || writer != NULL) - return EBUSY; - - return 0; -} - -int -pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) -{ - pthread_descr self = NULL; - pthread_readlock_info *existing; - int out_of_mem, have_lock_already; - - have_lock_already = rwlock_have_already(&self, rwlock, - &existing, &out_of_mem); - - for (;;) - { - if (self == NULL) - self = thread_self (); - - __pthread_lock (&rwlock->__rw_lock, self); - - if (rwlock_can_rdlock(rwlock, have_lock_already)) - break; - - enqueue (&rwlock->__rw_read_waiting, self); - __pthread_unlock (&rwlock->__rw_lock); - suspend (self); /* This is not a cancellation point */ - } - - ++rwlock->__rw_readers; - __pthread_unlock (&rwlock->__rw_lock); - - if (have_lock_already || out_of_mem) - { - if (existing != NULL) - existing->pr_lock_count++; - else - self->p_untracked_readlock_count++; - } - - return 0; -} - -int -pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) -{ - pthread_descr self = thread_self(); - pthread_readlock_info *existing; - int out_of_mem, have_lock_already; - int retval = EBUSY; - - have_lock_already = rwlock_have_already(&self, rwlock, - &existing, &out_of_mem); - - __pthread_lock (&rwlock->__rw_lock, self); - - /* 0 is passed to here instead of have_lock_already. - This is to meet Single Unix Spec requirements: - if writers are waiting, pthread_rwlock_tryrdlock - does not acquire a read lock, even if the caller has - one or more read locks already. */ - - if (rwlock_can_rdlock(rwlock, 0)) - { - ++rwlock->__rw_readers; - retval = 0; - } - - __pthread_unlock (&rwlock->__rw_lock); - - if (retval == 0) - { - if (have_lock_already || out_of_mem) - { - if (existing != NULL) - existing->pr_lock_count++; - else - self->p_untracked_readlock_count++; - } - } - - return retval; -} - - -int -pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) -{ - pthread_descr self = thread_self (); - - while(1) - { - __pthread_lock (&rwlock->__rw_lock, self); - if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) - { - rwlock->__rw_writer = self; - __pthread_unlock (&rwlock->__rw_lock); - return 0; - } - - /* Suspend ourselves, then try again */ - enqueue (&rwlock->__rw_write_waiting, self); - __pthread_unlock (&rwlock->__rw_lock); - suspend (self); /* This is not a cancellation point */ - } -} - - -int -pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) -{ - int result = EBUSY; - - __pthread_lock (&rwlock->__rw_lock, NULL); - if (rwlock->__rw_readers == 0 && rwlock->__rw_writer == NULL) - { - rwlock->__rw_writer = thread_self (); - result = 0; - } - __pthread_unlock (&rwlock->__rw_lock); - - return result; -} - - -int -pthread_rwlock_unlock (pthread_rwlock_t *rwlock) -{ - pthread_descr torestart; - pthread_descr th; - - __pthread_lock (&rwlock->__rw_lock, NULL); - if (rwlock->__rw_writer != NULL) - { - /* Unlocking a write lock. */ - if (rwlock->__rw_writer != thread_self ()) - { - __pthread_unlock (&rwlock->__rw_lock); - return EPERM; - } - rwlock->__rw_writer = NULL; - - if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_READER_NP - || (th = dequeue (&rwlock->__rw_write_waiting)) == NULL) - { - /* Restart all waiting readers. */ - torestart = rwlock->__rw_read_waiting; - rwlock->__rw_read_waiting = NULL; - __pthread_unlock (&rwlock->__rw_lock); - while ((th = dequeue (&torestart)) != NULL) - restart (th); - } - else - { - /* Restart one waiting writer. */ - __pthread_unlock (&rwlock->__rw_lock); - restart (th); - } - } - else - { - /* Unlocking a read lock. */ - if (rwlock->__rw_readers == 0) - { - __pthread_unlock (&rwlock->__rw_lock); - return EPERM; - } - - --rwlock->__rw_readers; - if (rwlock->__rw_readers == 0) - /* Restart one waiting writer, if any. */ - th = dequeue (&rwlock->__rw_write_waiting); - else - th = NULL; - - __pthread_unlock (&rwlock->__rw_lock); - if (th != NULL) - restart (th); - - /* Recursive lock fixup */ - - if (rwlock->__rw_kind == PTHREAD_RWLOCK_PREFER_WRITER_NP) - { - pthread_descr self = thread_self(); - pthread_readlock_info *victim = rwlock_remove_from_list(self, rwlock); - - if (victim != NULL) - { - if (victim->pr_lock_count == 0) - { - victim->pr_next = self->p_readlock_free; - self->p_readlock_free = victim; - } - } - else - { - if (self->p_untracked_readlock_count > 0) - self->p_untracked_readlock_count--; - } - } - } - - return 0; -} - - - -int -pthread_rwlockattr_init (pthread_rwlockattr_t *attr) -{ - attr->__lockkind = 0; - attr->__pshared = 0; - - return 0; -} - - -int -pthread_rwlockattr_destroy (pthread_rwlockattr_t *attr) -{ - return 0; -} - - -int -pthread_rwlockattr_getpshared (const pthread_rwlockattr_t *attr, int *pshared) -{ - *pshared = attr->__pshared; - return 0; -} - - -int -pthread_rwlockattr_setpshared (pthread_rwlockattr_t *attr, int pshared) -{ - if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) - return EINVAL; - - attr->__pshared = pshared; - - return 0; -} - - -int -pthread_rwlockattr_getkind_np (const pthread_rwlockattr_t *attr, int *pref) -{ - *pref = attr->__lockkind; - return 0; -} - - -int -pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref) -{ - if (pref != PTHREAD_RWLOCK_PREFER_READER_NP - && pref != PTHREAD_RWLOCK_PREFER_WRITER_NP - && pref != PTHREAD_RWLOCK_DEFAULT_NP) - return EINVAL; - - attr->__lockkind = pref; - - return 0; -} diff --git a/libpthread/linuxthreads/semaphore.c b/libpthread/linuxthreads/semaphore.c deleted file mode 100644 index 5be1f5316..000000000 --- a/libpthread/linuxthreads/semaphore.c +++ /dev/null @@ -1,308 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Semaphores a la POSIX 1003.1b */ - -#include -#define __USE_GNU -#include -#include "pthread.h" -#include "semaphore.h" -#include "internals.h" -#include "spinlock.h" -#include "restart.h" -#include "queue.h" - -int __new_sem_init(sem_t *sem, int pshared, unsigned int value) -{ - if (value > SEM_VALUE_MAX) { - errno = EINVAL; - return -1; - } - if (pshared) { - errno = ENOSYS; - return -1; - } - __pthread_init_lock(&sem->__sem_lock); - sem->__sem_value = value; - sem->__sem_waiting = NULL; - return 0; -} - -/* Function called by pthread_cancel to remove the thread from - waiting inside __new_sem_wait. */ - -static int new_sem_extricate_func(void *obj, pthread_descr th) -{ - volatile pthread_descr self = thread_self(); - sem_t *sem = obj; - int did_remove = 0; - - __pthread_lock(&sem->__sem_lock, self); - did_remove = remove_from_queue(&sem->__sem_waiting, th); - __pthread_unlock(&sem->__sem_lock); - - return did_remove; -} - -int __new_sem_wait(sem_t * sem) -{ - volatile pthread_descr self = thread_self(); - pthread_extricate_if extr; - int already_canceled = 0; - int spurious_wakeup_count; - - /* Set up extrication interface */ - extr.pu_object = sem; - extr.pu_extricate_func = new_sem_extricate_func; - - __pthread_lock(&sem->__sem_lock, self); - if (sem->__sem_value > 0) { - sem->__sem_value--; - __pthread_unlock(&sem->__sem_lock); - return 0; - } - /* Register extrication interface */ - THREAD_SETMEM(self, p_sem_avail, 0); - __pthread_set_own_extricate_if(self, &extr); - /* Enqueue only if not already cancelled. */ - if (!(THREAD_GETMEM(self, p_canceled) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) - enqueue(&sem->__sem_waiting, self); - else - already_canceled = 1; - __pthread_unlock(&sem->__sem_lock); - - if (already_canceled) { - __pthread_set_own_extricate_if(self, 0); - pthread_exit(PTHREAD_CANCELED); - } - - /* Wait for sem_post or cancellation, or fall through if already canceled */ - spurious_wakeup_count = 0; - while (1) - { - suspend(self); - if (THREAD_GETMEM(self, p_sem_avail) == 0 - && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 - || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) - { - /* Count resumes that don't belong to us. */ - spurious_wakeup_count++; - continue; - } - break; - } - __pthread_set_own_extricate_if(self, 0); - - /* Terminate only if the wakeup came from cancellation. */ - /* Otherwise ignore cancellation because we got the semaphore. */ - - if (THREAD_GETMEM(self, p_woken_by_cancel) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { - THREAD_SETMEM(self, p_woken_by_cancel, 0); - pthread_exit(PTHREAD_CANCELED); - } - /* We got the semaphore */ - return 0; -} - -int __new_sem_trywait(sem_t * sem) -{ - int retval; - - __pthread_lock(&sem->__sem_lock, NULL); - if (sem->__sem_value == 0) { - errno = EAGAIN; - retval = -1; - } else { - sem->__sem_value--; - retval = 0; - } - __pthread_unlock(&sem->__sem_lock); - return retval; -} - -int __new_sem_post(sem_t * sem) -{ - pthread_descr self = thread_self(); - pthread_descr th; - struct pthread_request request; - - if (THREAD_GETMEM(self, p_in_sighandler) == NULL) { - __pthread_lock(&sem->__sem_lock, self); - if (sem->__sem_waiting == NULL) { - if (sem->__sem_value >= SEM_VALUE_MAX) { - /* Overflow */ - errno = ERANGE; - __pthread_unlock(&sem->__sem_lock); - return -1; - } - sem->__sem_value++; - __pthread_unlock(&sem->__sem_lock); - } else { - th = dequeue(&sem->__sem_waiting); - __pthread_unlock(&sem->__sem_lock); - th->p_sem_avail = 1; - WRITE_MEMORY_BARRIER(); - restart(th); - } - } else { - /* If we're in signal handler, delegate post operation to - the thread manager. */ - if (__pthread_manager_request < 0) { - if (__pthread_initialize_manager() < 0) { - errno = EAGAIN; - return -1; - } - } - request.req_kind = REQ_POST; - request.req_args.post = sem; - TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, - (char *) &request, sizeof(request))); - } - return 0; -} - -int __new_sem_getvalue(sem_t * sem, int * sval) -{ - *sval = sem->__sem_value; - return 0; -} - -int __new_sem_destroy(sem_t * sem) -{ - if (sem->__sem_waiting != NULL) { - __set_errno (EBUSY); - return -1; - } - return 0; -} - -sem_t *sem_open(const char *name, int oflag, ...) -{ - __set_errno (ENOSYS); - return SEM_FAILED; -} - -int sem_close(sem_t *sem) -{ - __set_errno (ENOSYS); - return -1; -} - -int sem_unlink(const char *name) -{ - __set_errno (ENOSYS); - return -1; -} - -int sem_timedwait(sem_t *sem, const struct timespec *abstime) -{ - pthread_descr self = thread_self(); - pthread_extricate_if extr; - int already_canceled = 0; - int spurious_wakeup_count; - - __pthread_lock(&sem->__sem_lock, self); - if (sem->__sem_value > 0) { - --sem->__sem_value; - __pthread_unlock(&sem->__sem_lock); - return 0; - } - - if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) { - /* The standard requires that if the function would block and the - time value is illegal, the function returns with an error. */ - __pthread_unlock(&sem->__sem_lock); - __set_errno (EINVAL); - return -1; - } - - /* Set up extrication interface */ - extr.pu_object = sem; - extr.pu_extricate_func = new_sem_extricate_func; - - /* Register extrication interface */ - THREAD_SETMEM(self, p_sem_avail, 0); - __pthread_set_own_extricate_if(self, &extr); - /* Enqueue only if not already cancelled. */ - if (!(THREAD_GETMEM(self, p_canceled) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) - enqueue(&sem->__sem_waiting, self); - else - already_canceled = 1; - __pthread_unlock(&sem->__sem_lock); - - if (already_canceled) { - __pthread_set_own_extricate_if(self, 0); - pthread_exit(PTHREAD_CANCELED); - } - - spurious_wakeup_count = 0; - while (1) - { - if (timedsuspend(self, abstime) == 0) { - int was_on_queue; - - /* __pthread_lock will queue back any spurious restarts that - may happen to it. */ - - __pthread_lock(&sem->__sem_lock, self); - was_on_queue = remove_from_queue(&sem->__sem_waiting, self); - __pthread_unlock(&sem->__sem_lock); - - if (was_on_queue) { - __pthread_set_own_extricate_if(self, 0); - __set_errno (ETIMEDOUT); - return -1; - } - - /* Eat the outstanding restart() from the signaller */ - suspend(self); - } - - if (THREAD_GETMEM(self, p_sem_avail) == 0 - && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 - || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) - { - /* Count resumes that don't belong to us. */ - spurious_wakeup_count++; - continue; - } - break; - } - - __pthread_set_own_extricate_if(self, 0); - - /* Terminate only if the wakeup came from cancellation. */ - /* Otherwise ignore cancellation because we got the semaphore. */ - - if (THREAD_GETMEM(self, p_woken_by_cancel) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { - THREAD_SETMEM(self, p_woken_by_cancel, 0); - pthread_exit(PTHREAD_CANCELED); - } - /* We got the semaphore */ - return 0; -} - - -weak_alias (__new_sem_init, sem_init) -weak_alias (__new_sem_wait, sem_wait) -weak_alias (__new_sem_trywait, sem_trywait) -weak_alias (__new_sem_post, sem_post) -weak_alias (__new_sem_getvalue, sem_getvalue) -weak_alias (__new_sem_destroy, sem_destroy) - diff --git a/libpthread/linuxthreads/semaphore.h b/libpthread/linuxthreads/semaphore.h deleted file mode 100644 index 7b09ea931..000000000 --- a/libpthread/linuxthreads/semaphore.h +++ /dev/null @@ -1,87 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -#ifndef _SEMAPHORE_H -#define _SEMAPHORE_H 1 - -#include -#include -#ifdef __USE_XOPEN2K -# define __need_timespec -# include -#endif - -#ifndef _PTHREAD_DESCR_DEFINED -/* Thread descriptors. Needed for `sem_t' definition. */ -typedef struct _pthread_descr_struct *_pthread_descr; -# define _PTHREAD_DESCR_DEFINED -#endif - -/* System specific semaphore definition. */ -typedef struct -{ - struct _pthread_fastlock __sem_lock; - int __sem_value; - _pthread_descr __sem_waiting; -} sem_t; - - - -/* Value returned if `sem_open' failed. */ -#define SEM_FAILED ((sem_t *) 0) - -/* Maximum value the semaphore can have. */ -#define SEM_VALUE_MAX ((int) ((~0u) >> 1)) - - -__BEGIN_DECLS - -/* Initialize semaphore object SEM to VALUE. If PSHARED then share it - with other processes. */ -extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value) __THROW; - -/* Free resources associated with semaphore object SEM. */ -extern int sem_destroy (sem_t *__sem) __THROW; - -/* Open a named semaphore NAME with open flaot OFLAG. */ -extern sem_t *sem_open (__const char *__name, int __oflag, ...) __THROW; - -/* Close descriptor for named semaphore SEM. */ -extern int sem_close (sem_t *__sem) __THROW; - -/* Remove named semaphore NAME. */ -extern int sem_unlink (__const char *__name) __THROW; - -/* Wait for SEM being posted. */ -extern int sem_wait (sem_t *__sem); - -#ifdef __USE_XOPEN2K -/* Similar to `sem_wait' but wait only until ABSTIME. */ -extern int sem_timedwait (sem_t *__restrict __sem, - __const struct timespec *__restrict __abstime); -#endif - -/* Test whether SEM is posted. */ -extern int sem_trywait (sem_t *__sem) __THROW; - -/* Post SEM. */ -extern int sem_post (sem_t *__sem) __THROW; - -/* Get current value of SEM and store it in *SVAL. */ -extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval) - __THROW; - -__END_DECLS - -#endif /* semaphore.h */ diff --git a/libpthread/linuxthreads/signals.c b/libpthread/linuxthreads/signals.c deleted file mode 100644 index df15b884e..000000000 --- a/libpthread/linuxthreads/signals.c +++ /dev/null @@ -1,248 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Handling of signals */ - -#include -#include -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include -#include - -/* mods for uClibc: __libc_sigaction is not in any standard headers */ -extern int __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact); - -int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask) -{ - sigset_t mask; - - if (newmask != NULL) { - mask = *newmask; - /* Don't allow __pthread_sig_restart to be unmasked. - Don't allow __pthread_sig_cancel to be masked. */ - switch(how) { - case SIG_SETMASK: - sigaddset(&mask, __pthread_sig_restart); - sigdelset(&mask, __pthread_sig_cancel); - if (__pthread_sig_debug > 0) - sigdelset(&mask, __pthread_sig_debug); - break; - case SIG_BLOCK: - sigdelset(&mask, __pthread_sig_cancel); - if (__pthread_sig_debug > 0) - sigdelset(&mask, __pthread_sig_debug); - break; - case SIG_UNBLOCK: - sigdelset(&mask, __pthread_sig_restart); - break; - } - newmask = &mask; - } - if (sigprocmask(how, newmask, oldmask) == -1) - return errno; - else - return 0; -} - -int pthread_kill(pthread_t thread, int signo) -{ - pthread_handle handle = thread_handle(thread); - int pid; - - __pthread_lock(&handle->h_lock, NULL); - if (invalid_handle(handle, thread)) { - __pthread_unlock(&handle->h_lock); - return ESRCH; - } - pid = handle->h_descr->p_pid; - __pthread_unlock(&handle->h_lock); - if (kill(pid, signo) == -1) - return errno; - else - return 0; -} - -/* User-provided signal handlers */ -typedef void (*arch_sighandler_t) __PMT ((int, SIGCONTEXT)); -static union -{ - arch_sighandler_t old; - void (*rt) (int, struct siginfo *, struct ucontext *); -} sighandler[NSIG]; - -/* The wrapper around user-provided signal handlers */ -static void pthread_sighandler(int signo, SIGCONTEXT ctx) -{ - pthread_descr self = thread_self(); - char * in_sighandler; - /* If we're in a sigwait operation, just record the signal received - and return without calling the user's handler */ - if (THREAD_GETMEM(self, p_sigwaiting)) { - THREAD_SETMEM(self, p_sigwaiting, 0); - THREAD_SETMEM(self, p_signal, signo); - return; - } - /* Record that we're in a signal handler and call the user's - handler function */ - in_sighandler = THREAD_GETMEM(self, p_in_sighandler); - if (in_sighandler == NULL) - THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); - sighandler[signo].old(signo, SIGCONTEXT_EXTRA_ARGS ctx); - if (in_sighandler == NULL) - THREAD_SETMEM(self, p_in_sighandler, NULL); -} - -/* The same, this time for real-time signals. */ -static void pthread_sighandler_rt(int signo, struct siginfo *si, - struct ucontext *uc) -{ - pthread_descr self = thread_self(); - char * in_sighandler; - /* If we're in a sigwait operation, just record the signal received - and return without calling the user's handler */ - if (THREAD_GETMEM(self, p_sigwaiting)) { - THREAD_SETMEM(self, p_sigwaiting, 0); - THREAD_SETMEM(self, p_signal, signo); - return; - } - /* Record that we're in a signal handler and call the user's - handler function */ - in_sighandler = THREAD_GETMEM(self, p_in_sighandler); - if (in_sighandler == NULL) - THREAD_SETMEM(self, p_in_sighandler, CURRENT_STACK_FRAME); - sighandler[signo].rt(signo, si, uc); - if (in_sighandler == NULL) - THREAD_SETMEM(self, p_in_sighandler, NULL); -} - -/* The wrapper around sigaction. Install our own signal handler - around the signal. */ -int __sigaction(int sig, const struct sigaction * act, - struct sigaction * oact) -{ - struct sigaction newact; - struct sigaction *newactp; - -#ifdef DEBUG_PT -printf(__FUNCTION__": pthreads wrapper!\n"); -#endif - if (sig == __pthread_sig_restart || - sig == __pthread_sig_cancel || - (sig == __pthread_sig_debug && __pthread_sig_debug > 0)) - return EINVAL; - if (act) - { - newact = *act; - if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL - && sig > 0 && sig < NSIG) - { - if (act->sa_flags & SA_SIGINFO) - newact.sa_handler = (__sighandler_t) pthread_sighandler_rt; - else - newact.sa_handler = (__sighandler_t) pthread_sighandler; - } - newactp = &newact; - } - else - newactp = NULL; - if (__libc_sigaction(sig, newactp, oact) == -1) - return -1; -#ifdef DEBUG_PT -printf(__FUNCTION__": signahdler installed, __sigaction successful\n"); -#endif - if (sig > 0 && sig < NSIG) - { - if (oact != NULL) - oact->sa_handler = (__sighandler_t) sighandler[sig].old; - if (act) - /* For the assignment is does not matter whether it's a normal - or real-time signal. */ - sighandler[sig].old = (arch_sighandler_t) act->sa_handler; - } - return 0; -} -strong_alias(__sigaction, sigaction) - -/* A signal handler that does nothing */ -static void pthread_null_sighandler(int sig) { } - -/* sigwait -- synchronously wait for a signal */ -int sigwait(const sigset_t * set, int * sig) -{ - volatile pthread_descr self = thread_self(); - sigset_t mask; - int s; - sigjmp_buf jmpbuf; - struct sigaction sa; - - /* Get ready to block all signals except those in set - and the cancellation signal. - Also check that handlers are installed on all signals in set, - and if not, install our dummy handler. This is conformant to - POSIX: "The effect of sigwait() on the signal actions for the - signals in set is unspecified." */ - sigfillset(&mask); - sigdelset(&mask, __pthread_sig_cancel); - for (s = 1; s <= NSIG; s++) { - if (sigismember(set, s) && - s != __pthread_sig_restart && - s != __pthread_sig_cancel && - s != __pthread_sig_debug) { - sigdelset(&mask, s); - if (sighandler[s].old == NULL || - sighandler[s].old == (arch_sighandler_t) SIG_DFL || - sighandler[s].old == (arch_sighandler_t) SIG_IGN) { - sa.sa_handler = pthread_null_sighandler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(s, &sa, NULL); - } - } - } - /* Test for cancellation */ - if (sigsetjmp(jmpbuf, 1) == 0) { - THREAD_SETMEM(self, p_cancel_jmp, &jmpbuf); - if (! (THREAD_GETMEM(self, p_canceled) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) { - /* Reset the signal count */ - THREAD_SETMEM(self, p_signal, 0); - /* Say we're in sigwait */ - THREAD_SETMEM(self, p_sigwaiting, 1); - /* Unblock the signals and wait for them */ - sigsuspend(&mask); - } - } - THREAD_SETMEM(self, p_cancel_jmp, NULL); - /* The signals are now reblocked. Check for cancellation */ - pthread_testcancel(); - /* We should have self->p_signal != 0 and equal to the signal received */ - *sig = THREAD_GETMEM(self, p_signal); - return 0; -} - -/* Redefine raise() to send signal to calling thread only, - as per POSIX 1003.1c */ -int raise (int sig) -{ - int retcode = pthread_kill(pthread_self(), sig); - if (retcode == 0) - return 0; - else { - errno = retcode; - return -1; - } -} diff --git a/libpthread/linuxthreads/specific.c b/libpthread/linuxthreads/specific.c deleted file mode 100644 index d8b5bb0b3..000000000 --- a/libpthread/linuxthreads/specific.c +++ /dev/null @@ -1,204 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Thread-specific data */ - -#include -#define __USE_GNU -#include -#include -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "restart.h" - - -/* Table of keys. */ - -static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] = - { { 0, NULL } }; - -/* For debugging purposes put the maximum number of keys in a variable. */ -const int __linuxthreads_pthread_keys_max = PTHREAD_KEYS_MAX; -const int __linuxthreads_pthread_key_2ndlevel_size = PTHREAD_KEY_2NDLEVEL_SIZE; - -/* Mutex to protect access to pthread_keys */ - -static pthread_mutex_t pthread_keys_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* Create a new key */ - -int pthread_key_create(pthread_key_t * key, destr_function destr) -{ - int i; - - pthread_mutex_lock(&pthread_keys_mutex); - for (i = 0; i < PTHREAD_KEYS_MAX; i++) { - if (! pthread_keys[i].in_use) { - /* Mark key in use */ - pthread_keys[i].in_use = 1; - pthread_keys[i].destr = destr; - pthread_mutex_unlock(&pthread_keys_mutex); - *key = i; - return 0; - } - } - pthread_mutex_unlock(&pthread_keys_mutex); - return EAGAIN; -} - -/* Delete a key */ -int pthread_key_delete(pthread_key_t key) -{ - pthread_descr self = thread_self(); - - pthread_mutex_lock(&pthread_keys_mutex); - if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) { - pthread_mutex_unlock(&pthread_keys_mutex); - return EINVAL; - } - pthread_keys[key].in_use = 0; - pthread_keys[key].destr = NULL; - - /* Set the value of the key to NULL in all running threads, so - that if the key is reallocated later by pthread_key_create, its - associated values will be NULL in all threads. - Do nothing if no threads have been created yet. */ - if (__pthread_manager_request != -1) - { - pthread_descr th; - unsigned int idx1st, idx2nd; - - idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; - idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; - th = self; - do { - /* If the thread already is terminated don't modify the memory. */ - if (!th->p_terminated && th->p_specific[idx1st] != NULL) - th->p_specific[idx1st][idx2nd] = NULL; - th = th->p_nextlive; - } while (th != self); - } - - pthread_mutex_unlock(&pthread_keys_mutex); - return 0; -} - -/* Set the value of a key */ - -int pthread_setspecific(pthread_key_t key, const void * pointer) -{ - pthread_descr self = thread_self(); - unsigned int idx1st, idx2nd; - - if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) - return EINVAL; - idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; - idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; - if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL) { - void *newp = calloc(PTHREAD_KEY_2NDLEVEL_SIZE, sizeof (void *)); - if (newp == NULL) - return ENOMEM; - THREAD_SETMEM_NC(self, p_specific[idx1st], newp); - } - THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd] = (void *) pointer; - return 0; -} - -/* Get the value of a key */ - -void * pthread_getspecific(pthread_key_t key) -{ - pthread_descr self = thread_self(); - unsigned int idx1st, idx2nd; - - if (key >= PTHREAD_KEYS_MAX) - return NULL; - idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE; - idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE; - if (THREAD_GETMEM_NC(self, p_specific[idx1st]) == NULL - || !pthread_keys[key].in_use) - return NULL; - return THREAD_GETMEM_NC(self, p_specific[idx1st])[idx2nd]; -} - -/* Call the destruction routines on all keys */ - -void __pthread_destroy_specifics() -{ - pthread_descr self = thread_self(); - int i, j, round, found_nonzero; - destr_function destr; - void * data; - - for (round = 0, found_nonzero = 1; - found_nonzero && round < PTHREAD_DESTRUCTOR_ITERATIONS; - round++) { - found_nonzero = 0; - for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) - if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) - for (j = 0; j < PTHREAD_KEY_2NDLEVEL_SIZE; j++) { - destr = pthread_keys[i * PTHREAD_KEY_2NDLEVEL_SIZE + j].destr; - data = THREAD_GETMEM_NC(self, p_specific[i])[j]; - if (destr != NULL && data != NULL) { - THREAD_GETMEM_NC(self, p_specific[i])[j] = NULL; - destr(data); - found_nonzero = 1; - } - } - } - __pthread_lock(THREAD_GETMEM(self, p_lock), self); - for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) { - if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) { - free(THREAD_GETMEM_NC(self, p_specific[i])); - THREAD_SETMEM_NC(self, p_specific[i], NULL); - } - } - __pthread_unlock(THREAD_GETMEM(self, p_lock)); -} - - -/* Thread-specific data for libc. */ -#if !(USE_TLS && HAVE___THREAD) -static int -libc_internal_tsd_set(enum __libc_tsd_key_t key, const void * pointer) -{ - pthread_descr self = thread_self(); - - THREAD_SETMEM_NC(self, p_libc_specific[key], (void *) pointer); - return 0; -} -int (*__libc_internal_tsd_set)(enum __libc_tsd_key_t key, const void * pointer) - = libc_internal_tsd_set; - -static void * -libc_internal_tsd_get(enum __libc_tsd_key_t key) -{ - pthread_descr self = thread_self(); - - return THREAD_GETMEM_NC(self, p_libc_specific[key]); -} -void * (*__libc_internal_tsd_get)(enum __libc_tsd_key_t key) - = libc_internal_tsd_get; - -static void ** __attribute__ ((__const__)) -libc_internal_tsd_address (enum __libc_tsd_key_t key) -{ - pthread_descr self = thread_self(); - return &self->p_libc_specific[key]; -} -void **(*const __libc_internal_tsd_address) (enum __libc_tsd_key_t key) - __THROW __attribute__ ((__const__)) = libc_internal_tsd_address; -#endif diff --git a/libpthread/linuxthreads/spinlock.c b/libpthread/linuxthreads/spinlock.c deleted file mode 100644 index cdf45f195..000000000 --- a/libpthread/linuxthreads/spinlock.c +++ /dev/null @@ -1,723 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -/* Internal locks */ - -#define __FORCE_GLIBC -#include -#include -#include -#include -#include -#include -#include "pthread.h" -#include "internals.h" -#include "spinlock.h" -#include "restart.h" - -static void __pthread_acquire(int * spinlock); - -static inline void __pthread_release(int * spinlock) -{ - WRITE_MEMORY_BARRIER(); - *spinlock = __LT_SPINLOCK_INIT; - __asm __volatile ("" : "=m" (*spinlock) : "m" (*spinlock)); -} - - -/* The status field of a spinlock is a pointer whose least significant - bit is a locked flag. - - Thus the field values have the following meanings: - - status == 0: spinlock is free - status == 1: spinlock is taken; no thread is waiting on it - - (status & 1) == 1: spinlock is taken and (status & ~1L) is a - pointer to the first waiting thread; other - waiting threads are linked via the p_nextlock - field. - (status & 1) == 0: same as above, but spinlock is not taken. - - The waiting list is not sorted by priority order. - Actually, we always insert at top of list (sole insertion mode - that can be performed without locking). - For __pthread_unlock, we perform a linear search in the list - to find the highest-priority, oldest waiting thread. - This is safe because there are no concurrent __pthread_unlock - operations -- only the thread that locked the mutex can unlock it. */ - - -void internal_function __pthread_lock(struct _pthread_fastlock * lock, - pthread_descr self) -{ -#if defined HAS_COMPARE_AND_SWAP - long oldstatus, newstatus; - int successful_seizure, spurious_wakeup_count; - int spin_count; -#endif - -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - __pthread_acquire(&lock->__spinlock); - return; - } -#endif - -#if defined HAS_COMPARE_AND_SWAP - /* First try it without preparation. Maybe it's a completely - uncontested lock. */ - if (lock->__status == 0 && __compare_and_swap (&lock->__status, 0, 1)) - return; - - spurious_wakeup_count = 0; - spin_count = 0; - - /* On SMP, try spinning to get the lock. */ -#if 0 - if (__pthread_smp_kernel) { - int max_count = lock->__spinlock * 2 + 10; - - if (max_count > MAX_ADAPTIVE_SPIN_COUNT) - max_count = MAX_ADAPTIVE_SPIN_COUNT; - - for (spin_count = 0; spin_count < max_count; spin_count++) { - if (((oldstatus = lock->__status) & 1) == 0) { - if(__compare_and_swap(&lock->__status, oldstatus, oldstatus | 1)) - { - if (spin_count) - lock->__spinlock += (spin_count - lock->__spinlock) / 8; - READ_MEMORY_BARRIER(); - return; - } - } -#ifdef BUSY_WAIT_NOP - BUSY_WAIT_NOP; -#endif - __asm __volatile ("" : "=m" (lock->__status) : "m" (lock->__status)); - } - - lock->__spinlock += (spin_count - lock->__spinlock) / 8; - } -#endif - -again: - - /* No luck, try once more or suspend. */ - - do { - oldstatus = lock->__status; - successful_seizure = 0; - - if ((oldstatus & 1) == 0) { - newstatus = oldstatus | 1; - successful_seizure = 1; - } else { - if (self == NULL) - self = thread_self(); - newstatus = (long) self | 1; - } - - if (self != NULL) { - THREAD_SETMEM(self, p_nextlock, (pthread_descr) (oldstatus)); - /* Make sure the store in p_nextlock completes before performing - the compare-and-swap */ - MEMORY_BARRIER(); - } - } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); - - /* Suspend with guard against spurious wakeup. - This can happen in pthread_cond_timedwait_relative, when the thread - wakes up due to timeout and is still on the condvar queue, and then - locks the queue to remove itself. At that point it may still be on the - queue, and may be resumed by a condition signal. */ - - if (!successful_seizure) { - for (;;) { - suspend(self); - if (self->p_nextlock != NULL) { - /* Count resumes that don't belong to us. */ - spurious_wakeup_count++; - continue; - } - break; - } - goto again; - } - - /* Put back any resumes we caught that don't belong to us. */ - while (spurious_wakeup_count--) - restart(self); - - READ_MEMORY_BARRIER(); -#endif -} - -int __pthread_unlock(struct _pthread_fastlock * lock) -{ -#if defined HAS_COMPARE_AND_SWAP - long oldstatus; - pthread_descr thr, * ptr, * maxptr; - int maxprio; -#endif - -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - __pthread_release(&lock->__spinlock); - return 0; - } -#endif - -#if defined HAS_COMPARE_AND_SWAP - WRITE_MEMORY_BARRIER(); - -again: - while ((oldstatus = lock->__status) == 1) { - if (__compare_and_swap_with_release_semantics(&lock->__status, - oldstatus, 0)) - return 0; - } - - /* Find thread in waiting queue with maximal priority */ - ptr = (pthread_descr *) &lock->__status; - thr = (pthread_descr) (oldstatus & ~1L); - maxprio = 0; - maxptr = ptr; - - /* Before we iterate over the wait queue, we need to execute - a read barrier, otherwise we may read stale contents of nodes that may - just have been inserted by other processors. One read barrier is enough to - ensure we have a stable list; we don't need one for each pointer chase - through the list, because we are the owner of the lock; other threads - can only add nodes at the front; if a front node is consistent, - the ones behind it must also be. */ - - READ_MEMORY_BARRIER(); - - while (thr != 0) { - if (thr->p_priority >= maxprio) { - maxptr = ptr; - maxprio = thr->p_priority; - } - ptr = &(thr->p_nextlock); - thr = (pthread_descr)((long)(thr->p_nextlock) & ~1L); - } - - /* Remove max prio thread from waiting list. */ - if (maxptr == (pthread_descr *) &lock->__status) { - /* If max prio thread is at head, remove it with compare-and-swap - to guard against concurrent lock operation. This removal - also has the side effect of marking the lock as released - because the new status comes from thr->p_nextlock whose - least significant bit is clear. */ - thr = (pthread_descr) (oldstatus & ~1L); - if (! __compare_and_swap_with_release_semantics - (&lock->__status, oldstatus, (long)(thr->p_nextlock) & ~1L)) - goto again; - } else { - /* No risk of concurrent access, remove max prio thread normally. - But in this case we must also flip the least significant bit - of the status to mark the lock as released. */ - thr = (pthread_descr)((long)*maxptr & ~1L); - *maxptr = thr->p_nextlock; - - /* Ensure deletion from linked list completes before we - release the lock. */ - WRITE_MEMORY_BARRIER(); - - do { - oldstatus = lock->__status; - } while (!__compare_and_swap_with_release_semantics(&lock->__status, - oldstatus, oldstatus & ~1L)); - } - - /* Wake up the selected waiting thread. Woken thread can check - its own p_nextlock field for NULL to detect that it has been removed. No - barrier is needed here, since restart() and suspend() take - care of memory synchronization. */ - - thr->p_nextlock = NULL; - restart(thr); - - return 0; -#endif -} - -/* - * Alternate fastlocks do not queue threads directly. Instead, they queue - * these wait queue node structures. When a timed wait wakes up due to - * a timeout, it can leave its wait node in the queue (because there - * is no safe way to remove from the quue). Some other thread will - * deallocate the abandoned node. - */ - - -struct wait_node { - struct wait_node *next; /* Next node in null terminated linked list */ - pthread_descr thr; /* The thread waiting with this node */ - int abandoned; /* Atomic flag */ -}; - -static long wait_node_free_list; -static int wait_node_free_list_spinlock; - -/* Allocate a new node from the head of the free list using an atomic - operation, or else using malloc if that list is empty. A fundamental - assumption here is that we can safely access wait_node_free_list->next. - That's because we never free nodes once we allocate them, so a pointer to a - node remains valid indefinitely. */ - -static struct wait_node *wait_node_alloc(void) -{ - struct wait_node *new_node = 0; - - __pthread_acquire(&wait_node_free_list_spinlock); - if (wait_node_free_list != 0) { - new_node = (struct wait_node *) wait_node_free_list; - wait_node_free_list = (long) new_node->next; - } - WRITE_MEMORY_BARRIER(); - __pthread_release(&wait_node_free_list_spinlock); - - if (new_node == 0) - return malloc(sizeof *wait_node_alloc()); - - return new_node; -} - -/* Return a node to the head of the free list using an atomic - operation. */ - -static void wait_node_free(struct wait_node *wn) -{ - __pthread_acquire(&wait_node_free_list_spinlock); - wn->next = (struct wait_node *) wait_node_free_list; - wait_node_free_list = (long) wn; - WRITE_MEMORY_BARRIER(); - __pthread_release(&wait_node_free_list_spinlock); - return; -} - -#if defined HAS_COMPARE_AND_SWAP - -/* Remove a wait node from the specified queue. It is assumed - that the removal takes place concurrently with only atomic insertions at the - head of the queue. */ - -static void wait_node_dequeue(struct wait_node **pp_head, - struct wait_node **pp_node, - struct wait_node *p_node) -{ - /* If the node is being deleted from the head of the - list, it must be deleted using atomic compare-and-swap. - Otherwise it can be deleted in the straightforward way. */ - - if (pp_node == pp_head) { - /* We don't need a read barrier between these next two loads, - because it is assumed that the caller has already ensured - the stability of *p_node with respect to p_node. */ - - long oldvalue = (long) p_node; - long newvalue = (long) p_node->next; - - if (__compare_and_swap((long *) pp_node, oldvalue, newvalue)) - return; - - /* Oops! Compare and swap failed, which means the node is - no longer first. We delete it using the ordinary method. But we don't - know the identity of the node which now holds the pointer to the node - being deleted, so we must search from the beginning. */ - - for (pp_node = pp_head; p_node != *pp_node; ) { - pp_node = &(*pp_node)->next; - READ_MEMORY_BARRIER(); /* Stabilize *pp_node for next iteration. */ - } - } - - *pp_node = p_node->next; - return; -} - -#endif - -void __pthread_alt_lock(struct _pthread_fastlock * lock, - pthread_descr self) -{ -#if defined HAS_COMPARE_AND_SWAP - long oldstatus, newstatus; -#endif - struct wait_node wait_node; - -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - int suspend_needed = 0; - __pthread_acquire(&lock->__spinlock); - - if (lock->__status == 0) - lock->__status = 1; - else { - if (self == NULL) - self = thread_self(); - - wait_node.abandoned = 0; - wait_node.next = (struct wait_node *) lock->__status; - wait_node.thr = self; - lock->__status = (long) &wait_node; - suspend_needed = 1; - } - - __pthread_release(&lock->__spinlock); - - if (suspend_needed) - suspend (self); - return; - } -#endif - -#if defined HAS_COMPARE_AND_SWAP - do { - oldstatus = lock->__status; - if (oldstatus == 0) { - newstatus = 1; - } else { - if (self == NULL) - self = thread_self(); - wait_node.thr = self; - newstatus = (long) &wait_node; - } - wait_node.abandoned = 0; - wait_node.next = (struct wait_node *) oldstatus; - /* Make sure the store in wait_node.next completes before performing - the compare-and-swap */ - MEMORY_BARRIER(); - } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); - - /* Suspend. Note that unlike in __pthread_lock, we don't worry - here about spurious wakeup. That's because this lock is not - used in situations where that can happen; the restart can - only come from the previous lock owner. */ - - if (oldstatus != 0) - suspend(self); - - READ_MEMORY_BARRIER(); -#endif -} - -/* Timed-out lock operation; returns 0 to indicate timeout. */ - -int __pthread_alt_timedlock(struct _pthread_fastlock * lock, - pthread_descr self, const struct timespec *abstime) -{ - long oldstatus = 0; -#if defined HAS_COMPARE_AND_SWAP - long newstatus; -#endif - struct wait_node *p_wait_node = wait_node_alloc(); - - /* Out of memory, just give up and do ordinary lock. */ - if (p_wait_node == 0) { - __pthread_alt_lock(lock, self); - return 1; - } - -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - __pthread_acquire(&lock->__spinlock); - - if (lock->__status == 0) - lock->__status = 1; - else { - if (self == NULL) - self = thread_self(); - - p_wait_node->abandoned = 0; - p_wait_node->next = (struct wait_node *) lock->__status; - p_wait_node->thr = self; - lock->__status = (long) p_wait_node; - oldstatus = 1; /* force suspend */ - } - - __pthread_release(&lock->__spinlock); - goto suspend; - } -#endif - -#if defined HAS_COMPARE_AND_SWAP - do { - oldstatus = lock->__status; - if (oldstatus == 0) { - newstatus = 1; - } else { - if (self == NULL) - self = thread_self(); - p_wait_node->thr = self; - newstatus = (long) p_wait_node; - } - p_wait_node->abandoned = 0; - p_wait_node->next = (struct wait_node *) oldstatus; - /* Make sure the store in wait_node.next completes before performing - the compare-and-swap */ - MEMORY_BARRIER(); - } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus)); -#endif - -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - suspend: -#endif - - /* If we did not get the lock, do a timed suspend. If we wake up due - to a timeout, then there is a race; the old lock owner may try - to remove us from the queue. This race is resolved by us and the owner - doing an atomic testandset() to change the state of the wait node from 0 - to 1. If we succeed, then it's a timeout and we abandon the node in the - queue. If we fail, it means the owner gave us the lock. */ - - if (oldstatus != 0) { - if (timedsuspend(self, abstime) == 0) { - if (!testandset(&p_wait_node->abandoned)) - return 0; /* Timeout! */ - - /* Eat oustanding resume from owner, otherwise wait_node_free() below - will race with owner's wait_node_dequeue(). */ - suspend(self); - } - } - - wait_node_free(p_wait_node); - - READ_MEMORY_BARRIER(); - - return 1; /* Got the lock! */ -} - -void __pthread_alt_unlock(struct _pthread_fastlock *lock) -{ - struct wait_node *p_node, **pp_node, *p_max_prio, **pp_max_prio; - struct wait_node ** const pp_head = (struct wait_node **) &lock->__status; - int maxprio; - - WRITE_MEMORY_BARRIER(); - -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - __pthread_acquire(&lock->__spinlock); - } -#endif - - while (1) { - - /* If no threads are waiting for this lock, try to just - atomically release it. */ -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - if (lock->__status == 0 || lock->__status == 1) { - lock->__status = 0; - break; - } - } -#endif - -#if defined TEST_FOR_COMPARE_AND_SWAP - else -#endif - -#if defined HAS_COMPARE_AND_SWAP - { - long oldstatus = lock->__status; - if (oldstatus == 0 || oldstatus == 1) { - if (__compare_and_swap_with_release_semantics (&lock->__status, oldstatus, 0)) - break; - else - continue; - } - } -#endif - - /* Process the entire queue of wait nodes. Remove all abandoned - wait nodes and put them into the global free queue, and - remember the one unabandoned node which refers to the thread - having the highest priority. */ - - pp_max_prio = pp_node = pp_head; - p_max_prio = p_node = *pp_head; - maxprio = INT_MIN; - - READ_MEMORY_BARRIER(); /* Prevent access to stale data through p_node */ - - while (p_node != (struct wait_node *) 1) { - int prio; - - if (p_node->abandoned) { - /* Remove abandoned node. */ -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - *pp_node = p_node->next; -#endif -#if defined TEST_FOR_COMPARE_AND_SWAP - else -#endif -#if defined HAS_COMPARE_AND_SWAP - wait_node_dequeue(pp_head, pp_node, p_node); -#endif - wait_node_free(p_node); - /* Note that the next assignment may take us to the beginning - of the queue, to newly inserted nodes, if pp_node == pp_head. - In that case we need a memory barrier to stabilize the first of - these new nodes. */ - p_node = *pp_node; - if (pp_node == pp_head) - READ_MEMORY_BARRIER(); /* No stale reads through p_node */ - continue; - } else if ((prio = p_node->thr->p_priority) >= maxprio) { - /* Otherwise remember it if its thread has a higher or equal priority - compared to that of any node seen thus far. */ - maxprio = prio; - pp_max_prio = pp_node; - p_max_prio = p_node; - } - - /* This canno6 jump backward in the list, so no further read - barrier is needed. */ - pp_node = &p_node->next; - p_node = *pp_node; - } - - /* If all threads abandoned, go back to top */ - if (maxprio == INT_MIN) - continue; - - ASSERT (p_max_prio != (struct wait_node *) 1); - - /* Now we want to to remove the max priority thread's wait node from - the list. Before we can do this, we must atomically try to change the - node's abandon state from zero to nonzero. If we succeed, that means we - have the node that we will wake up. If we failed, then it means the - thread timed out and abandoned the node in which case we repeat the - whole unlock operation. */ - - if (!testandset(&p_max_prio->abandoned)) { -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - *pp_max_prio = p_max_prio->next; -#endif -#if defined TEST_FOR_COMPARE_AND_SWAP - else -#endif -#if defined HAS_COMPARE_AND_SWAP - wait_node_dequeue(pp_head, pp_max_prio, p_max_prio); -#endif - restart(p_max_prio->thr); - break; - } - } - -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - __pthread_release(&lock->__spinlock); - } -#endif -} - - -/* Compare-and-swap emulation with a spinlock */ - -#ifdef TEST_FOR_COMPARE_AND_SWAP -int __pthread_has_cas = 0; -#endif - -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - -int __pthread_compare_and_swap(long * ptr, long oldval, long newval, - int * spinlock) -{ - int res; - - __pthread_acquire(spinlock); - - if (*ptr == oldval) { - *ptr = newval; res = 1; - } else { - res = 0; - } - - __pthread_release(spinlock); - - return res; -} - -#endif - -/* The retry strategy is as follows: - - We test and set the spinlock MAX_SPIN_COUNT times, calling - sched_yield() each time. This gives ample opportunity for other - threads with priority >= our priority to make progress and - release the spinlock. - - If a thread with priority < our priority owns the spinlock, - calling sched_yield() repeatedly is useless, since we're preventing - the owning thread from making progress and releasing the spinlock. - So, after MAX_SPIN_LOCK attemps, we suspend the calling thread - using nanosleep(). This again should give time to the owning thread - for releasing the spinlock. - Notice that the nanosleep() interval must not be too small, - since the kernel does busy-waiting for short intervals in a realtime - process (!). The smallest duration that guarantees thread - suspension is currently 2ms. - - When nanosleep() returns, we try again, doing MAX_SPIN_COUNT - sched_yield(), then sleeping again if needed. */ - -static void __pthread_acquire(int * spinlock) -{ - int cnt = 0; - struct timespec tm; - - READ_MEMORY_BARRIER(); - - while (testandset(spinlock)) { - if (cnt < MAX_SPIN_COUNT) { - sched_yield(); - cnt++; - } else { - tm.tv_sec = 0; - tm.tv_nsec = SPIN_SLEEP_DURATION; - nanosleep(&tm, NULL); - cnt = 0; - } - } -} diff --git a/libpthread/linuxthreads/spinlock.h b/libpthread/linuxthreads/spinlock.h deleted file mode 100644 index 0ec40c57c..000000000 --- a/libpthread/linuxthreads/spinlock.h +++ /dev/null @@ -1,218 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -#include - - -/* There are 2 compare and swap synchronization primitives with - different semantics: - - 1. compare_and_swap, which has acquire semantics (i.e. it - completes befor subsequent writes.) - 2. compare_and_swap_with_release_semantics, which has release - semantics (it completes after previous writes.) - - For those platforms on which they are the same. HAS_COMPARE_AND_SWAP - should be defined. For those platforms on which they are different, - HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS has to be defined. */ - -#ifndef HAS_COMPARE_AND_SWAP -#ifdef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS -#define HAS_COMPARE_AND_SWAP -#endif -#endif - -#if defined(TEST_FOR_COMPARE_AND_SWAP) - -extern int __pthread_has_cas; -extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval, - int * spinlock); - -static inline int compare_and_swap(long * ptr, long oldval, long newval, - int * spinlock) -{ - if (__builtin_expect (__pthread_has_cas, 1)) - return __compare_and_swap(ptr, oldval, newval); - else - return __pthread_compare_and_swap(ptr, oldval, newval, spinlock); -} - -#elif defined(HAS_COMPARE_AND_SWAP) - -#ifdef IMPLEMENT_TAS_WITH_CAS -#define testandset(p) !__compare_and_swap((long int *) p, 0, 1) -#endif - -#ifdef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS - -static inline int -compare_and_swap_with_release_semantics (long * ptr, long oldval, - long newval, int * spinlock) -{ - return __compare_and_swap_with_release_semantics (ptr, oldval, - newval); -} - -#endif - -static inline int compare_and_swap(long * ptr, long oldval, long newval, - int * spinlock) -{ - return __compare_and_swap(ptr, oldval, newval); -} - -#else - -extern int __pthread_compare_and_swap(long * ptr, long oldval, long newval, - int * spinlock); - -static inline int compare_and_swap(long * ptr, long oldval, long newval, - int * spinlock) -{ - return __pthread_compare_and_swap(ptr, oldval, newval, spinlock); -} - -#endif - -#ifndef HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS -#define compare_and_swap_with_release_semantics compare_and_swap -#define __compare_and_swap_with_release_semantics __compare_and_swap -#endif - -/* Internal locks */ - -extern void internal_function __pthread_lock(struct _pthread_fastlock * lock, - pthread_descr self); -extern int __pthread_unlock(struct _pthread_fastlock *lock); - -static inline void __pthread_init_lock(struct _pthread_fastlock * lock) -{ - lock->__status = 0; - lock->__spinlock = __LT_SPINLOCK_INIT; -} - -static inline int __pthread_trylock (struct _pthread_fastlock * lock) -{ -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - return (testandset(&lock->__spinlock) ? EBUSY : 0); - } -#endif - -#if defined HAS_COMPARE_AND_SWAP - do { - if (lock->__status != 0) return EBUSY; - } while(! __compare_and_swap(&lock->__status, 0, 1)); - return 0; -#endif -} - -/* Variation of internal lock used for pthread_mutex_t, supporting - timed-out waits. Warning: do not mix these operations with the above ones - over the same lock object! */ - -extern void __pthread_alt_lock(struct _pthread_fastlock * lock, - pthread_descr self); - -extern int __pthread_alt_timedlock(struct _pthread_fastlock * lock, - pthread_descr self, const struct timespec *abstime); - -extern void __pthread_alt_unlock(struct _pthread_fastlock *lock); - -static inline void __pthread_alt_init_lock(struct _pthread_fastlock * lock) -{ - lock->__status = 0; - lock->__spinlock = __LT_SPINLOCK_INIT; -} - -static inline int __pthread_alt_trylock (struct _pthread_fastlock * lock) -{ -#if defined TEST_FOR_COMPARE_AND_SWAP - if (!__pthread_has_cas) -#endif -#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP - { - int res = EBUSY; - - if (testandset(&lock->__spinlock) == 0) - { - if (lock->__status == 0) - { - lock->__status = 1; - WRITE_MEMORY_BARRIER(); - res = 0; - } - lock->__spinlock = __LT_SPINLOCK_INIT; - } - return res; - } -#endif - -#if defined HAS_COMPARE_AND_SWAP - do { - if (lock->__status != 0) return EBUSY; - } while(! compare_and_swap(&lock->__status, 0, 1, &lock->__spinlock)); - return 0; -#endif -} - -/* Operations on pthread_atomic, which is defined in internals.h */ - -static inline long atomic_increment(struct pthread_atomic *pa) -{ - long oldval; - - do { - oldval = pa->p_count; - } while (!compare_and_swap(&pa->p_count, oldval, oldval + 1, &pa->p_spinlock)); - - return oldval; -} - - -static inline long atomic_decrement(struct pthread_atomic *pa) -{ - long oldval; - - do { - oldval = pa->p_count; - } while (!compare_and_swap(&pa->p_count, oldval, oldval - 1, &pa->p_spinlock)); - - return oldval; -} - - -static inline void -__pthread_set_own_extricate_if (pthread_descr self, pthread_extricate_if *peif) -{ - /* Only store a non-null peif if the thread has cancellation enabled. - Otherwise pthread_cancel will unconditionally call the extricate handler, - and restart the thread giving rise to forbidden spurious wakeups. */ - if (peif == NULL - || THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) - { - /* If we are removing the extricate interface, we need to synchronize - against pthread_cancel so that it does not continue with a pointer - to a deallocated pthread_extricate_if struct! The thread lock - is (ab)used for this synchronization purpose. */ - if (peif == NULL) - __pthread_lock (THREAD_GETMEM(self, p_lock), self); - THREAD_SETMEM(self, p_extricate, peif); - if (peif == NULL) - __pthread_unlock (THREAD_GETMEM(self, p_lock)); - } -} diff --git a/libpthread/linuxthreads/sysdeps/alpha/pt-machine.h b/libpthread/linuxthreads/sysdeps/alpha/pt-machine.h deleted file mode 100644 index 853ac6f04..000000000 --- a/libpthread/linuxthreads/sysdeps/alpha/pt-machine.h +++ /dev/null @@ -1,128 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - Alpha version. - Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -#ifdef __linux__ -# include -#else -# include -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char *stack_pointer __asm__("$30"); - - -/* Memory barrier; default is to do nothing */ -#define MEMORY_BARRIER() __asm__ __volatile__("mb" : : : "memory") -/* Write barrier. */ -#define WRITE_MEMORY_BARRIER() __asm__ __volatile__("wmb" : : : "memory") - - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - long int ret, temp; - - __asm__ __volatile__( - "/* Inline spinlock test & set */\n" - "1:\t" - "ldl_l %0,%3\n\t" - "bne %0,2f\n\t" - "or $31,1,%1\n\t" - "stl_c %1,%2\n\t" - "beq %1,1b\n" - "2:\tmb\n" - "/* End spinlock test & set */" - : "=&r"(ret), "=&r"(temp), "=m"(*spinlock) - : "m"(*spinlock) - : "memory"); - - return ret; -} - - -/* Begin allocating thread stacks at this address. Default is to allocate - them just below the initial program stack. */ -#define THREAD_STACK_START_ADDRESS 0x40000000000 - - -/* Return the thread descriptor for the current thread. */ -#define THREAD_SELF \ -({ \ - register pthread_descr __self __asm__("$0"); \ - __asm__ ("call_pal %1" : "=r"(__self) : "i"(PAL_rduniq)); \ - __self; \ -}) - -/* Initialize the thread-unique value. */ -#define INIT_THREAD_SELF(descr, nr) \ -{ \ - register pthread_descr __self __asm__("$16") = (descr); \ - __asm__ __volatile__ ("call_pal %1" : : "r"(__self), "i"(PAL_wruniq)); \ -} - - -/* Compare-and-swap for semaphores. */ - -#define HAS_COMPARE_AND_SWAP -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - long int ret; - - __asm__ __volatile__ ( - "/* Inline compare & swap */\n" - "1:\t" - "ldq_l %0,%4\n\t" - "cmpeq %0,%2,%0\n\t" - "beq %0,2f\n\t" - "mov %3,%0\n\t" - "stq_c %0,%1\n\t" - "beq %0,1b\n\t" - "2:\tmb\n" - "/* End compare & swap */" - : "=&r"(ret), "=m"(*p) - : "r"(oldval), "r"(newval), "m"(*p) - : "memory"); - - return ret; -} - -/* We want the OS to assign stack addresses. */ -#define FLOATING_STACKS 1 - -/* Maximum size of the stack if the rlimit is unlimited. */ -#define ARCH_STACK_MAX_SIZE 32*1024*1024 - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/arm/pt-machine.h b/libpthread/linuxthreads/sysdeps/arm/pt-machine.h deleted file mode 100644 index 284567970..000000000 --- a/libpthread/linuxthreads/sysdeps/arm/pt-machine.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - ARM version. - Copyright (C) 1997, 1998, 2000, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Philip Blundell . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* This will not work on ARM1 or ARM2 because SWP is lacking on those - machines. Unfortunately we have no way to detect this at compile - time; let's hope nobody tries to use one. */ - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - register unsigned int ret; - -#if defined(__thumb__) - void *pc; - __asm__ __volatile__( - ".align 0\n" - "\tbx pc\n" - "\tnop\n" - "\t.arm\n" - "\tswp %0, %2, [%3]\n" - "\torr %1, pc, #1\n" - "\tbx %1\n" - "\t.force_thumb" - : "=r"(ret), "=r"(pc) - : "0"(1), "r"(spinlock)); -#else - __asm__ __volatile__("swp %0, %1, [%2]" - : "=r"(ret) - : "0"(1), "r"(spinlock)); -#endif - - return ret; -} - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("sp"); - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/bfin/pt-machine.h b/libpthread/linuxthreads/sysdeps/bfin/pt-machine.h deleted file mode 100644 index fef16263e..000000000 --- a/libpthread/linuxthreads/sysdeps/bfin/pt-machine.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - Copyright (C) 1996, 1998, 2000, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long *, long , long); - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - if (*spinlock) - return 1; - else - { - *spinlock=1; - return 0; - } -} - -#define HAS_COMPARE_AND_SWAP - -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - if((*p ^ oldval) == 0) { - *p = newval; - return 1; - } - else - return 0; -} - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/cris/pt-machine.h b/libpthread/linuxthreads/sysdeps/cris/pt-machine.h deleted file mode 100644 index 431da7101..000000000 --- a/libpthread/linuxthreads/sysdeps/cris/pt-machine.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - CRIS version. - Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -PT_EI long int -testandset (int *spinlock) -{ - register unsigned long int ret; - - /* Note the use of a dummy output of *spinlock to expose the write. The - memory barrier is to stop *other* writes being moved past this code. */ - __asm__ __volatile__("clearf\n" - "0:\n\t" - "movu.b [%2],%0\n\t" - "ax\n\t" - "move.b %3,[%2]\n\t" - "bwf 0b\n\t" - "clearf" - : "=&r" (ret), "=m" (*spinlock) - : "r" (spinlock), "r" ((int) 1) - : "memory"); - return ret; -} - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. - I don't trust register variables, so let's do this the safe way. */ -#define CURRENT_STACK_FRAME \ - ({ char *sp; __asm__ ("move.d $sp,%0" : "=rm" (sp)); sp; }) - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/frv/pt-machine.h b/libpthread/linuxthreads/sysdeps/frv/pt-machine.h deleted file mode 100644 index 64df5ffdb..000000000 --- a/libpthread/linuxthreads/sysdeps/frv/pt-machine.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - FR-V version. - Copyright (C) 2004 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Alexandre Oliva - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef __ASSEMBLER__ - -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - int i = 1; - asm ("swap%I0 %M0, %1" : "+m"(*(volatile int *)spinlock), "+r"(i)); - return i; -} - -/* We want the OS to assign stack addresses. */ -#define FLOATING_STACKS 1 - -/* This symbol is defined by the ABI as the stack size requested by - the main program. */ -extern char __stacksize; -#define ARCH_STACK_MAX_SIZE ((unsigned long)&__stacksize) - -/* Memory barrier; default is to do nothing */ -#define MEMORY_BARRIER() __asm__ __volatile__("membar" : : : "memory") -/* Write barrier. */ -#define WRITE_MEMORY_BARRIER() __asm__ __volatile__("membar" : : : "memory") - -/* Return the thread descriptor for the current thread. */ -register struct _pthread_descr_struct *THREAD_SELF asm ("gr29"); -#define THREAD_SELF THREAD_SELF - -/* Initialize the thread-unique value. */ -#define INIT_THREAD_SELF(descr, nr) \ - (THREAD_SELF = descr) - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("sp"); - -#endif - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/i386/pt-machine.h b/libpthread/linuxthreads/sysdeps/i386/pt-machine.h deleted file mode 100644 index af1818d7b..000000000 --- a/libpthread/linuxthreads/sysdeps/i386/pt-machine.h +++ /dev/null @@ -1,158 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - i386 version. - Copyright (C) 1996-2001, 2002, 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef __ASSEMBLER__ -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME __builtin_frame_address (0) - - -/* See if we can optimize for newer cpus... */ -#if defined __GNUC__ && __GNUC__ >= 2 && \ - (defined __i486__ || defined __pentium__ || defined __pentiumpro__ || defined __pentium4__ || \ - defined __athlon__ || defined __k8__) - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - long int ret; - - __asm__ __volatile__ ( - "xchgl %0, %1" - : "=r" (ret), "=m" (*spinlock) - : "0" (1), "m" (*spinlock) - : "memory"); - - return ret; -} - -/* Compare-and-swap for semaphores. It's always available on i686. */ -#define HAS_COMPARE_AND_SWAP - -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - char ret; - long int readval; - - __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" - : "=q" (ret), "=m" (*p), "=a" (readval) - : "r" (newval), "m" (*p), "a" (oldval) - : "memory"); - return ret; -} - -#if __ASSUME_LDT_WORKS > 0 -#include "../useldt.h" -#endif - -/* The P4 and above really want some help to prevent overheating. */ -#define BUSY_WAIT_NOP __asm__ ("rep; nop") - - -#else /* Generic i386 implementation */ - - - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - long int ret; - - __asm__ __volatile__( - "xchgl %0, %1" - : "=r"(ret), "=m"(*spinlock) - : "0"(1), "m"(*spinlock) - : "memory"); - - return ret; -} - - -/* Compare-and-swap for semaphores. - Available on the 486 and above, but not on the 386. - We test dynamically whether it's available or not. */ - -#define HAS_COMPARE_AND_SWAP -#define TEST_FOR_COMPARE_AND_SWAP - -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - char ret; - long int readval; - - __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0" - : "=q" (ret), "=m" (*p), "=a" (readval) - : "r" (newval), "m" (*p), "a" (oldval) - : "memory"); - return ret; -} - - -PT_EI int -get_eflags (void) -{ - int res; - __asm__ __volatile__ ("pushfl; popl %0" : "=r" (res) : ); - return res; -} - - -PT_EI void -set_eflags (int newflags) -{ - __asm__ __volatile__ ("pushl %0; popfl" : : "r" (newflags) : "cc"); -} - - -PT_EI int -compare_and_swap_is_available (void) -{ - int oldflags = get_eflags (); - int changed; - /* Flip AC bit in EFLAGS. */ - set_eflags (oldflags ^ 0x40000); - /* See if bit changed. */ - changed = (get_eflags () ^ oldflags) & 0x40000; - /* Restore EFLAGS. */ - set_eflags (oldflags); - /* If the AC flag did not change, it's a 386 and it lacks cmpxchg. - Otherwise, it's a 486 or above and it has cmpxchg. */ - return changed != 0; -} -#endif /* Generic i386 implementation */ - -#endif /* __ASSEMBLER__ */ - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/i386/tls.h b/libpthread/linuxthreads/sysdeps/i386/tls.h deleted file mode 100644 index e4f007ee3..000000000 --- a/libpthread/linuxthreads/sysdeps/i386/tls.h +++ /dev/null @@ -1,185 +0,0 @@ -/* Definition for thread-local data handling. linuxthreads/i386 version. - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _TLS_H -#define _TLS_H - -# include - -#ifndef __ASSEMBLER__ -# include -# include -# include - -/* Type for the dtv. */ -typedef union dtv -{ - size_t counter; - void *pointer; -} dtv_t; - - -typedef struct -{ - void *tcb; /* Pointer to the TCB. Not necessary the - thread descriptor used by libpthread. */ - dtv_t *dtv; - void *self; /* Pointer to the thread descriptor. */ -} tcbhead_t; -#endif - - -/* We can support TLS only if the floating-stack support is available. */ -#if defined FLOATING_STACKS && defined HAVE_TLS_SUPPORT - -/* Signal that TLS support is available. */ -//# define USE_TLS 1 - -# ifndef __ASSEMBLER__ -/* Get system call information. */ -# include - - -/* Get the thread descriptor definition. */ -# include - -/* This is the size of the initial TCB. */ -# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) - -/* Alignment requirements for the initial TCB. */ -# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) - -/* This is the size of the TCB. */ -# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) - -/* Alignment requirements for the TCB. */ -# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) - -/* The TCB can have any size and the memory following the address the - thread pointer points to is unspecified. Allocate the TCB there. */ -# define TLS_TCB_AT_TP 1 - - -/* Install the dtv pointer. The pointer passed is to the element with - index -1 which contain the length. */ -# define INSTALL_DTV(descr, dtvp) \ - ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 - -/* Install new dtv for current thread. */ -# define INSTALL_NEW_DTV(dtv) \ - ({ struct _pthread_descr_struct *__descr; \ - THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); }) - -/* Return dtv of given thread descriptor. */ -# define GET_DTV(descr) \ - (((tcbhead_t *) (descr))->dtv) - -# ifdef __PIC__ -# define TLS_EBX_ARG "r" -# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t" -# else -# define TLS_EBX_ARG "b" -# define TLS_LOAD_EBX -# endif - -# define TLS_DO_MODIFY_LDT(descr, nr) \ -({ \ - struct modify_ldt_ldt_s ldt_entry = \ - { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ - 1, 0, 0, 1, 0, 1, 0 }; \ - int result; \ - asm volatile (TLS_LOAD_EBX \ - "int $0x80\n\t" \ - TLS_LOAD_EBX \ - : "=a" (result) \ - : "0" (__NR_modify_ldt), \ - /* The extra argument with the "m" constraint is necessary \ - to let the compiler know that we are accessing LDT_ENTRY \ - here. */ \ - "m" (ldt_entry), TLS_EBX_ARG (1), "c" (&ldt_entry), \ - "d" (sizeof (ldt_entry))); \ - __builtin_expect (result, 0) != 0 ? -1 : nr * 8 + 7; \ -}) - -# define TLS_DO_SET_THREAD_AREA(descr, secondcall) \ -({ \ - struct modify_ldt_ldt_s ldt_entry = \ - { -1, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ - 1, 0, 0, 1, 0, 1, 0 }; \ - int result; \ - if (secondcall) \ - ldt_entry.entry_number = ({ int _gs; \ - asm ("movw %%gs, %w0" : "=q" (_gs)); \ - (_gs & 0xffff) >> 3; }); \ - asm volatile (TLS_LOAD_EBX \ - "int $0x80\n\t" \ - TLS_LOAD_EBX \ - : "=a" (result), "=m" (ldt_entry.entry_number) \ - : "0" (__NR_set_thread_area), \ - /* The extra argument with the "m" constraint is necessary \ - to let the compiler know that we are accessing LDT_ENTRY \ - here. */ \ - TLS_EBX_ARG (&ldt_entry), "m" (ldt_entry)); \ - __builtin_expect (result, 0) == 0 ? ldt_entry.entry_number * 8 + 3 : -1; \ -}) - -# ifdef __ASSUME_SET_THREAD_AREA_SYSCALL -# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ - TLS_DO_SET_THREAD_AREA (descr, firstcall) -# elif defined __NR_set_thread_area -# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ - ({ int __seg = TLS_DO_SET_THREAD_AREA (descr, secondcall); \ - __seg == -1 ? TLS_DO_MODIFY_LDT (descr, 0) : __seg; }) -# else -# define TLS_SETUP_GS_SEGMENT(descr, secondcall) \ - TLS_DO_MODIFY_LDT ((descr), 0) -# endif - -/* Code to initially initialize the thread pointer. This might need - special attention since 'errno' is not yet available and if the - operation can cause a failure 'errno' must not be touched. */ -# define TLS_INIT_TP(descr, secondcall) \ - ({ \ - void *_descr = (descr); \ - tcbhead_t *head = _descr; \ - int __gs; \ - \ - head->tcb = _descr; \ - /* For now the thread descriptor is at the same address. */ \ - head->self = _descr; \ - \ - __gs = TLS_SETUP_GS_SEGMENT (_descr, secondcall); \ - if (__builtin_expect (__gs, 7) != -1) \ - { \ - asm ("movw %w0, %%gs" : : "q" (__gs)); \ - __gs = 0; \ - } \ - __gs; \ - }) - - -/* Return the address of the dtv for the current thread. */ -# define THREAD_DTV() \ - ({ struct _pthread_descr_struct *__descr; \ - THREAD_GETMEM (__descr, p_header.data.dtvp); }) - -# endif /* FLOATING_STACKS && HAVE_TLS_SUPPORT */ -#endif /* __ASSEMBLER__ */ - -#endif /* tls.h */ diff --git a/libpthread/linuxthreads/sysdeps/i386/useldt.h b/libpthread/linuxthreads/sysdeps/i386/useldt.h deleted file mode 100644 index 16aee9989..000000000 --- a/libpthread/linuxthreads/sysdeps/i386/useldt.h +++ /dev/null @@ -1,307 +0,0 @@ -/* Special definitions for ix86 machine using segment register based - thread descriptor. - Copyright (C) 1998, 2000, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef __ASSEMBLER__ -#include /* For offsetof. */ -#include /* For abort(). */ - - -/* We don't want to include the kernel header. So duplicate the - information. */ - -/* Structure passed on `modify_ldt' call. */ -struct modify_ldt_ldt_s -{ - unsigned int entry_number; - unsigned long int base_addr; - unsigned int limit; - unsigned int seg_32bit:1; - unsigned int contents:2; - unsigned int read_exec_only:1; - unsigned int limit_in_pages:1; - unsigned int seg_not_present:1; - unsigned int useable:1; - unsigned int empty:25; -}; - -/* System call to set LDT entry. */ -extern int __modify_ldt (int, struct modify_ldt_ldt_s *, size_t); - - -/* Return the thread descriptor for the current thread. - - The contained asm must *not* be marked volatile since otherwise - assignments like - pthread_descr self = thread_self(); - do not get optimized away. */ -#define THREAD_SELF \ -({ \ - register pthread_descr __self; \ - __asm__ ("movl %%gs:%c1,%0" : "=r" (__self) \ - : "i" (offsetof (struct _pthread_descr_struct, \ - p_header.data.self))); \ - __self; \ -}) - - -/* Initialize the thread-unique value. Two possible ways to do it. */ - -#define DO_MODIFY_LDT(descr, nr) \ -({ \ - struct modify_ldt_ldt_s ldt_entry = \ - { nr, (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ - 1, 0, 0, 1, 0, 1, 0 }; \ - if (__modify_ldt (1, &ldt_entry, sizeof (ldt_entry)) != 0) \ - abort (); \ - asm ("movw %w0, %%gs" : : "q" (nr * 8 + 7)); \ -}) - -#ifdef __PIC__ -# define USETLS_EBX_ARG "r" -# define USETLS_LOAD_EBX "xchgl %3, %%ebx\n\t" -#else -# define USETLS_EBX_ARG "b" -# define USETLS_LOAD_EBX -#endif - -/* When using the new set_thread_area call, we don't need to change %gs - because we inherited the value set up in the main thread by TLS setup. - We need to extract that value and set up the same segment in this - thread. */ -#if USE_TLS -# define DO_SET_THREAD_AREA_REUSE(nr) 1 -#else -/* Without TLS, we do the initialization of the main thread, where NR == 0. */ -# define DO_SET_THREAD_AREA_REUSE(nr) (!__builtin_constant_p (nr) || (nr)) -#endif -#define DO_SET_THREAD_AREA(descr, nr) \ -({ \ - int __gs; \ - if (DO_SET_THREAD_AREA_REUSE (nr)) \ - { \ - asm ("movw %%gs, %w0" : "=q" (__gs)); \ - struct modify_ldt_ldt_s ldt_entry = \ - { (__gs & 0xffff) >> 3, \ - (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ - 1, 0, 0, 1, 0, 1, 0 }; \ - \ - int __result; \ - __asm (USETLS_LOAD_EBX \ - "movl %2, %%eax\n\t" \ - "int $0x80\n\t" \ - USETLS_LOAD_EBX \ - : "&a" (__result) \ - : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area)); \ - if (__result == 0) \ - asm ("movw %w0, %%gs" :: "q" (__gs)); \ - else \ - __gs = -1; \ - } \ - else \ - { \ - struct modify_ldt_ldt_s ldt_entry = \ - { -1, \ - (unsigned long int) (descr), 0xfffff /* 4GB in pages */, \ - 1, 0, 0, 1, 0, 1, 0 }; \ - int __result; \ - __asm (USETLS_LOAD_EBX \ - "movl %2, %%eax\n\t" \ - "int $0x80\n\t" \ - USETLS_LOAD_EBX \ - : "&a" (__result) \ - : USETLS_EBX_ARG (&ldt_entry), "i" (__NR_set_thread_area)); \ - if (__result == 0) \ - { \ - __gs = (ldt_entry.entry_number << 3) + 3; \ - asm ("movw %w0, %%gs" : : "q" (__gs)); \ - } \ - else \ - __gs = -1; \ - } \ - __gs; \ -}) - -#if defined __ASSUME_SET_THREAD_AREA_SYSCALL -# define INIT_THREAD_SELF(descr, nr) DO_SET_THREAD_AREA (descr, nr) -#elif defined __NR_set_thread_area -# define INIT_THREAD_SELF(descr, nr) \ -({ \ - if (__builtin_expect (__have_no_set_thread_area, 0) \ - || (DO_SET_THREAD_AREA (descr, DO_SET_THREAD_AREA_REUSE (nr)) == -1 \ - && (__have_no_set_thread_area = 1))) \ - DO_MODIFY_LDT (descr, nr); \ -}) -/* Defined in pspinlock.c. */ -extern int __have_no_set_thread_area; -#else -# define INIT_THREAD_SELF(descr, nr) DO_MODIFY_LDT (descr, nr) -#endif - -/* Free resources associated with thread descriptor. */ -#ifdef __ASSUME_SET_THREAD_AREA_SYSCALL -#define FREE_THREAD(descr, nr) do { } while (0) -#elif defined __NR_set_thread_area -#define FREE_THREAD(descr, nr) \ -{ \ - int __gs; \ - __asm__ __volatile__ ("movw %%gs, %w0" : "=q" (__gs)); \ - if (__builtin_expect (__gs & 4, 0)) \ - { \ - struct modify_ldt_ldt_s ldt_entry = \ - { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \ - __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \ - } \ -} -#else -#define FREE_THREAD(descr, nr) \ -{ \ - struct modify_ldt_ldt_s ldt_entry = \ - { nr, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; \ - __modify_ldt (1, &ldt_entry, sizeof (ldt_entry)); \ -} -#endif - -/* Read member of the thread descriptor directly. */ -#define THREAD_GETMEM(descr, member) \ -({ \ - __typeof__ (descr->member) __value; \ - if (sizeof (__value) == 1) \ - __asm__ __volatile__ ("movb %%gs:%P2,%b0" \ - : "=q" (__value) \ - : "0" (0), \ - "i" (offsetof (struct _pthread_descr_struct, \ - member))); \ - else if (sizeof (__value) == 4) \ - __asm__ __volatile__ ("movl %%gs:%P1,%0" \ - : "=r" (__value) \ - : "i" (offsetof (struct _pthread_descr_struct, \ - member))); \ - else \ - { \ - if (sizeof (__value) != 8) \ - /* There should not be any value with a size other than 1, 4 or 8. */\ - abort (); \ - \ - __asm__ __volatile__ ("movl %%gs:%P1,%%eax\n\t" \ - "movl %%gs:%P2,%%edx" \ - : "=A" (__value) \ - : "i" (offsetof (struct _pthread_descr_struct, \ - member)), \ - "i" (offsetof (struct _pthread_descr_struct, \ - member) + 4)); \ - } \ - __value; \ -}) - -/* Same as THREAD_GETMEM, but the member offset can be non-constant. */ -#define THREAD_GETMEM_NC(descr, member) \ -({ \ - __typeof__ (descr->member) __value; \ - if (sizeof (__value) == 1) \ - __asm__ __volatile__ ("movb %%gs:(%2),%b0" \ - : "=q" (__value) \ - : "0" (0), \ - "r" (offsetof (struct _pthread_descr_struct, \ - member))); \ - else if (sizeof (__value) == 4) \ - __asm__ __volatile__ ("movl %%gs:(%1),%0" \ - : "=r" (__value) \ - : "r" (offsetof (struct _pthread_descr_struct, \ - member))); \ - else \ - { \ - if (sizeof (__value) != 8) \ - /* There should not be any value with a size other than 1, 4 or 8. */\ - abort (); \ - \ - __asm__ __volatile__ ("movl %%gs:(%1),%%eax\n\t" \ - "movl %%gs:4(%1),%%edx" \ - : "=&A" (__value) \ - : "r" (offsetof (struct _pthread_descr_struct, \ - member))); \ - } \ - __value; \ -}) - -/* Same as THREAD_SETMEM, but the member offset can be non-constant. */ -#define THREAD_SETMEM(descr, member, value) \ -({ \ - __typeof__ (descr->member) __value = (value); \ - if (sizeof (__value) == 1) \ - __asm__ __volatile__ ("movb %0,%%gs:%P1" : \ - : "q" (__value), \ - "i" (offsetof (struct _pthread_descr_struct, \ - member))); \ - else if (sizeof (__value) == 4) \ - __asm__ __volatile__ ("movl %0,%%gs:%P1" : \ - : "r" (__value), \ - "i" (offsetof (struct _pthread_descr_struct, \ - member))); \ - else \ - { \ - if (sizeof (__value) != 8) \ - /* There should not be any value with a size other than 1, 4 or 8. */\ - abort (); \ - \ - __asm__ __volatile__ ("movl %%eax,%%gs:%P1\n\n" \ - "movl %%edx,%%gs:%P2" : \ - : "A" (__value), \ - "i" (offsetof (struct _pthread_descr_struct, \ - member)), \ - "i" (offsetof (struct _pthread_descr_struct, \ - member) + 4)); \ - } \ -}) - -/* Set member of the thread descriptor directly. */ -#define THREAD_SETMEM_NC(descr, member, value) \ -({ \ - __typeof__ (descr->member) __value = (value); \ - if (sizeof (__value) == 1) \ - __asm__ __volatile__ ("movb %0,%%gs:(%1)" : \ - : "q" (__value), \ - "r" (offsetof (struct _pthread_descr_struct, \ - member))); \ - else if (sizeof (__value) == 4) \ - __asm__ __volatile__ ("movl %0,%%gs:(%1)" : \ - : "r" (__value), \ - "r" (offsetof (struct _pthread_descr_struct, \ - member))); \ - else \ - { \ - if (sizeof (__value) != 8) \ - /* There should not be any value with a size other than 1, 4 or 8. */\ - abort (); \ - \ - __asm__ __volatile__ ("movl %%eax,%%gs:(%1)\n\t" \ - "movl %%edx,%%gs:4(%1)" : \ - : "A" (__value), \ - "r" (offsetof (struct _pthread_descr_struct, \ - member))); \ - } \ -}) -#endif - -/* We want the OS to assign stack addresses. */ -#define FLOATING_STACKS 1 - -/* Maximum size of the stack if the rlimit is unlimited. */ -#define ARCH_STACK_MAX_SIZE 8*1024*1024 diff --git a/libpthread/linuxthreads/sysdeps/m68k/pt-machine.h b/libpthread/linuxthreads/sysdeps/m68k/pt-machine.h deleted file mode 100644 index 4670ae3c4..000000000 --- a/libpthread/linuxthreads/sysdeps/m68k/pt-machine.h +++ /dev/null @@ -1,76 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - m68k version. - Copyright (C) 1996, 1998, 2000, 2002, 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - char ret; - - __asm__ __volatile__( -#if !defined(__mcoldfire__) && !defined(__mcf5200__) && !defined(__m68000) - "tas %1; sne %0" -#else - "bset #7,%1; sne %0" -#endif - : "=dm"(ret), "=m"(*spinlock) - : "m"(*spinlock) - : "cc"); - - return ret; -} - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("%sp"); - - -/* Compare-and-swap for semaphores. */ - -#if !defined(__mcoldfire__) && !defined(__mcf5200__) && !defined(__mc68000) -#define HAS_COMPARE_AND_SWAP -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - char ret; - long int readval; - - __asm__ __volatile__ ("casl %2, %3, %1; seq %0" - : "=dm" (ret), "=m" (*p), "=d" (readval) - : "d" (newval), "m" (*p), "2" (oldval)); - - return ret; -} -#endif - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/mips/pt-machine.h b/libpthread/linuxthreads/sysdeps/mips/pt-machine.h deleted file mode 100644 index f7efc881d..000000000 --- a/libpthread/linuxthreads/sysdeps/mips/pt-machine.h +++ /dev/null @@ -1,110 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - - Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ralf Baechle . - Based on the Alpha version by Richard Henderson . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#include - -/* Copyright (C) 2000, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Maciej W. Rozycki , 2000. */ -static inline int -_test_and_set (int *p, int v) __THROW -{ - int r, t; - - __asm__ __volatile__ - ("/* Inline test and set */\n" - "1:\n\t" - ".set push\n\t" - ".set mips2\n\t" - "ll %0,%3\n\t" - "move %1,%4\n\t" - "beq %0,%4,2f\n\t" - "sc %1,%2\n\t" - ".set pop\n\t" - "beqz %1,1b\n" - "2:\n\t" - "/* End test and set */" - : "=&r" (r), "=&r" (t), "=m" (*p) - : "m" (*p), "r" (v) - : "memory"); - - return r; -} - - -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - - -/* Spinlock implementation; required. */ - -PT_EI long int -testandset (int *spinlock) -{ - return _test_and_set (spinlock, 1); -} - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("$29"); - - -/* Compare-and-swap for semaphores. */ - -#define HAS_COMPARE_AND_SWAP -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - long int ret, temp; - - __asm__ __volatile__ - ("/* Inline compare & swap */\n" - "1:\n\t" - ".set push\n\t" - ".set mips2\n\t" - "ll %1,%5\n\t" - "move %0,$0\n\t" - "bne %1,%3,2f\n\t" - "move %0,%4\n\t" - "sc %0,%2\n\t" - ".set pop\n\t" - "beqz %0,1b\n" - "2:\n\t" - "/* End compare & swap */" - : "=&r" (ret), "=&r" (temp), "=m" (*p) - : "r" (oldval), "r" (newval), "m" (*p) - : "memory"); - - return ret; -} - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/nios/pt-machine.h b/libpthread/linuxthreads/sysdeps/nios/pt-machine.h deleted file mode 100644 index 5d82b8d16..000000000 --- a/libpthread/linuxthreads/sysdeps/nios/pt-machine.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - ARM version. - Copyright (C) 1997, 1998 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Philip Blundell . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline -#endif - -extern long int testandset (int *spinlock); -/* Spinlock implementation; required. */ -/* it is weird and dangerous to disable interrupt in userspace, but for nios - what else we can do before we have a swap like instruction? This is better - than nothing - */ -PT_EI long int -testandset (int *spinlock) -{ - unsigned int ret; - - __asm__ __volatile__("pfx 8\n\t" - "wrctl %1 ; disable interrupt\n\t" - "nop\n\t" - "nop\n\t" - "ld %0, [%2]\n\t" - "st [%2], %1\n\t" - "pfx 9\n\t" - "wrctl %1 ; enable interrupt\n\t" - "nop\n\t" - "nop\n\t" - : "=&r"(ret) - : "r"(1), "r"(spinlock) - : "memory"); - - return ret; -} - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("%sp"); - -/* nios needs more because of reg windows */ -#define THREAD_MANAGER_STACK_SIZE (32*1024) -#define STACK_SIZE (32*1024) - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/nios2/pt-machine.h b/libpthread/linuxthreads/sysdeps/nios2/pt-machine.h deleted file mode 100644 index 484a77e14..000000000 --- a/libpthread/linuxthreads/sysdeps/nios2/pt-machine.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - nios2 version. - Copyright (C) 1996, 1998, 2000, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline -#endif - -extern long int testandset (int *spinlock); - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - unsigned int scratch; - long int ret=-2; - - __asm__ __volatile__( - "rdctl %0, status\n\t" - "and %0, %0, %1\n\t" - "wrctl status, %0 #disable interrupts\n\t" - "ldw %1, 0(%4)\n\t" - "stw %3, 0(%4)\n\t" - "ori %0, %0, 1\n\t" - "wrctl status, %0 #enable interrupts\n\t" - : "=&r"(scratch), "=r"(ret) - : "1"(ret), "r"(1), "r"(spinlock) - : "memory"); - - return ret; -} - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("%sp"); - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/powerpc/pt-machine.h b/libpthread/linuxthreads/sysdeps/powerpc/pt-machine.h deleted file mode 100644 index 9e6543a26..000000000 --- a/libpthread/linuxthreads/sysdeps/powerpc/pt-machine.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - powerpc version. - Copyright (C) 1996, 1997, 1998, 2000, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* These routines are from Appendix G of the 'PowerPC 601 RISC Microprocessor - User's Manual', by IBM and Motorola. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* For multiprocessor systems, we want to ensure all memory accesses - are completed before we reset a lock. On other systems, we still - need to make sure that the compiler has flushed everything to memory. */ -#define MEMORY_BARRIER() __asm__ __volatile__ ("sync" : : : "memory") - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("r1"); - -/* Register r2 (tp) is reserved by the ABI as "thread pointer". */ -struct _pthread_descr_struct; -register struct _pthread_descr_struct *__thread_self __asm__("r2"); - -/* Return the thread descriptor for the current thread. */ -#define THREAD_SELF __thread_self - -/* Initialize the thread-unique value. */ -#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) - -/* Compare-and-swap for semaphores. */ -/* note that test-and-set(x) is the same as !compare-and-swap(x, 0, 1) */ - -#define HAS_COMPARE_AND_SWAP_WITH_RELEASE_SEMANTICS -#define IMPLEMENT_TAS_WITH_CAS - -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - int ret; - - __asm__ __volatile__ ( - "0: lwarx %0,0,%1 ;" - " xor. %0,%3,%0;" - " bne 1f;" - " stwcx. %2,0,%1;" - " bne- 0b;" - "1: " - : "=&r"(ret) - : "r"(p), "r"(newval), "r"(oldval) - : "cr0", "memory"); - /* This version of __compare_and_swap is to be used when acquiring - a lock, so we don't need to worry about whether other memory - operations have completed, but we do need to be sure that any loads - after this point really occur after we have acquired the lock. */ - __asm__ __volatile__ ("isync" : : : "memory"); - return ret == 0; -} - -PT_EI int -__compare_and_swap_with_release_semantics (long int *p, - long int oldval, long int newval) -{ - int ret; - - MEMORY_BARRIER (); - __asm__ __volatile__ ( - "0: lwarx %0,0,%1 ;" - " xor. %0,%3,%0;" - " bne 1f;" - " stwcx. %2,0,%1;" - " bne- 0b;" - "1: " - : "=&r"(ret) - : "r"(p), "r"(newval), "r"(oldval) - : "cr0", "memory"); - return ret == 0; -} - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h deleted file mode 100644 index e2b267d32..000000000 --- a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h +++ /dev/null @@ -1,328 +0,0 @@ -/* libc-internal interface for mutex locks. LinuxThreads version. - Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003 - Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _BITS_LIBC_LOCK_H -#define _BITS_LIBC_LOCK_H 1 - -#include - -/* Mutex type. */ -#if defined(_LIBC) || defined(_IO_MTSAFE_IO) -typedef pthread_mutex_t __libc_lock_t; -typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; -# ifdef __USE_UNIX98 -typedef pthread_rwlock_t __libc_rwlock_t; -# else -typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; -# endif -#else -typedef struct __libc_lock_opaque__ __libc_lock_t; -typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; -typedef struct __libc_rwlock_opaque__ __libc_rwlock_t; -#endif - -/* Type for key to thread-specific data. */ -typedef pthread_key_t __libc_key_t; - -/* Define a lock variable NAME with storage class CLASS. The lock must be - initialized with __libc_lock_init before it can be used (or define it - with __libc_lock_define_initialized, below). Use `extern' for CLASS to - declare a lock defined in another module. In public structure - definitions you must use a pointer to the lock structure (i.e., NAME - begins with a `*'), because its storage size will not be known outside - of libc. */ -#define __libc_lock_define(CLASS,NAME) \ - CLASS __libc_lock_t NAME; -#define __libc_rwlock_define(CLASS,NAME) \ - CLASS __libc_rwlock_t NAME; -#define __libc_lock_define_recursive(CLASS,NAME) \ - CLASS __libc_lock_recursive_t NAME; - -/* Define an initialized lock variable NAME with storage class CLASS. - - For the C library we take a deeper look at the initializer. For - this implementation all fields are initialized to zero. Therefore - we don't initialize the variable which allows putting it into the - BSS section. (Except on PA-RISC and other odd architectures, where - initialized locks must be set to one due to the lack of normal - atomic operations.) */ - -#if __LT_SPINLOCK_INIT == 0 -# define __libc_lock_define_initialized(CLASS,NAME) \ - CLASS __libc_lock_t NAME; -#else -# define __libc_lock_define_initialized(CLASS,NAME) \ - CLASS __libc_lock_t NAME = PTHREAD_MUTEX_INITIALIZER; -#endif - -#define __libc_rwlock_define_initialized(CLASS,NAME) \ - CLASS __libc_rwlock_t NAME = PTHREAD_RWLOCK_INITIALIZER; - -/* Define an initialized recursive lock variable NAME with storage - class CLASS. */ -#define __libc_lock_define_initialized_recursive(CLASS,NAME) \ - CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; -#define _LIBC_LOCK_RECURSIVE_INITIALIZER \ - {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} - -/* Initialize the named lock variable, leaving it in a consistent, unlocked - state. */ -#define __libc_lock_init(NAME) \ - (__pthread_mutex_init != NULL ? __pthread_mutex_init (&(NAME), NULL) : 0); -#define __libc_rwlock_init(NAME) \ - (__pthread_rwlock_init != NULL ? __pthread_rwlock_init (&(NAME), NULL) : 0); - -/* Same as last but this time we initialize a recursive mutex. */ -#define __libc_lock_init_recursive(NAME) \ - do { \ - if (__pthread_mutex_init != NULL) \ - { \ - pthread_mutexattr_t __attr; \ - __pthread_mutexattr_init (&__attr); \ - __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \ - __pthread_mutex_init (&(NAME).mutex, &__attr); \ - __pthread_mutexattr_destroy (&__attr); \ - } \ - } while (0); - -/* Finalize the named lock variable, which must be locked. It cannot be - used again until __libc_lock_init is called again on it. This must be - called on a lock variable before the containing storage is reused. */ -#define __libc_lock_fini(NAME) \ - (__pthread_mutex_destroy != NULL ? __pthread_mutex_destroy (&(NAME)) : 0); -#define __libc_rwlock_fini(NAME) \ - (__pthread_rwlock_destroy != NULL ? __pthread_rwlock_destroy (&(NAME)) : 0); - -/* Finalize recursive named lock. */ -#define __libc_lock_fini_recursive(NAME) __libc_lock_fini ((NAME).mutex) - -/* Lock the named lock variable. */ -#define __libc_lock_lock(NAME) \ - (__pthread_mutex_lock != NULL ? __pthread_mutex_lock (&(NAME)) : 0); -#define __libc_rwlock_rdlock(NAME) \ - (__pthread_rwlock_rdlock != NULL ? __pthread_rwlock_rdlock (&(NAME)) : 0); -#define __libc_rwlock_wrlock(NAME) \ - (__pthread_rwlock_wrlock != NULL ? __pthread_rwlock_wrlock (&(NAME)) : 0); - -/* Lock the recursive named lock variable. */ -#define __libc_lock_lock_recursive(NAME) __libc_lock_lock ((NAME).mutex) - -/* Try to lock the named lock variable. */ -#define __libc_lock_trylock(NAME) \ - (__pthread_mutex_trylock != NULL ? __pthread_mutex_trylock (&(NAME)) : 0) -#define __libc_rwlock_tryrdlock(NAME) \ - (__pthread_rwlock_tryrdlock != NULL \ - ? __pthread_rwlock_tryrdlock (&(NAME)) : 0) -#define __libc_rwlock_trywrlock(NAME) \ - (__pthread_rwlock_trywrlock != NULL \ - ? __pthread_rwlock_trywrlock (&(NAME)) : 0) - -/* Try to lock the recursive named lock variable. */ -#define __libc_lock_trylock_recursive(NAME) __libc_lock_trylock ((NAME).mutex) - -/* Unlock the named lock variable. */ -#define __libc_lock_unlock(NAME) \ - (__pthread_mutex_unlock != NULL ? __pthread_mutex_unlock (&(NAME)) : 0); -#define __libc_rwlock_unlock(NAME) \ - (__pthread_rwlock_unlock != NULL ? __pthread_rwlock_unlock (&(NAME)) : 0); - -/* Unlock the recursive named lock variable. */ -#define __libc_lock_unlock_recursive(NAME) __libc_lock_unlock ((NAME).mutex) - - -/* Define once control variable. */ -#if PTHREAD_ONCE_INIT == 0 -/* Special case for static variables where we can avoid the initialization - if it is zero. */ -# define __libc_once_define(CLASS, NAME) \ - CLASS pthread_once_t NAME -#else -# define __libc_once_define(CLASS, NAME) \ - CLASS pthread_once_t NAME = PTHREAD_ONCE_INIT -#endif - -/* Call handler iff the first call. */ -#define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \ - do { \ - if (__pthread_once != NULL) \ - __pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \ - else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \ - INIT_FUNCTION (); \ - (ONCE_CONTROL) = !PTHREAD_ONCE_INIT; \ - } \ - } while (0) - - -/* Start critical region with cleanup. */ -#define __libc_cleanup_region_start(DOIT, FCT, ARG) \ - { struct _pthread_cleanup_buffer _buffer; \ - int _avail = (DOIT) && _pthread_cleanup_push_defer != NULL; \ - if (_avail) { \ - _pthread_cleanup_push_defer (&_buffer, (FCT), (ARG)); \ - } - -/* End critical region with cleanup. */ -#define __libc_cleanup_region_end(DOIT) \ - if (_avail) { \ - _pthread_cleanup_pop_restore (&_buffer, (DOIT)); \ - } \ - } - -/* Sometimes we have to exit the block in the middle. */ -#define __libc_cleanup_end(DOIT) \ - if (_avail) { \ - _pthread_cleanup_pop_restore (&_buffer, (DOIT)); \ - } - -/* Create thread-specific key. */ -#define __libc_key_create(KEY, DESTRUCTOR) \ - (__pthread_key_create != NULL ? __pthread_key_create (KEY, DESTRUCTOR) : 1) - -/* Get thread-specific data. */ -#define __libc_getspecific(KEY) \ - (__pthread_getspecific != NULL ? __pthread_getspecific (KEY) : NULL) - -/* Set thread-specific data. */ -#define __libc_setspecific(KEY, VALUE) \ - (__pthread_setspecific != NULL ? __pthread_setspecific (KEY, VALUE) : 0) - - -/* Register handlers to execute before and after `fork'. */ -#define __libc_atfork(PREPARE, PARENT, CHILD) \ - (__pthread_atfork != NULL ? __pthread_atfork (PREPARE, PARENT, CHILD) : 0) - -/* Functions that are used by this file and are internal to the GNU C - library. */ - -extern int __pthread_mutex_init (pthread_mutex_t *__mutex, - __const pthread_mutexattr_t *__mutex_attr); - -extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); - -extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex); - -extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); - -extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); - -extern int __pthread_mutexattr_init (pthread_mutexattr_t *__attr); - -extern int __pthread_mutexattr_destroy (pthread_mutexattr_t *__attr); - -extern int __pthread_mutexattr_settype (pthread_mutexattr_t *__attr, - int __kind); - -#ifdef __USE_UNIX98 -extern int __pthread_rwlock_init (pthread_rwlock_t *__rwlock, - __const pthread_rwlockattr_t *__attr); - -extern int __pthread_rwlock_destroy (pthread_rwlock_t *__rwlock); - -extern int __pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock); - -extern int __pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock); - -extern int __pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock); - -extern int __pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock); - -extern int __pthread_rwlock_unlock (pthread_rwlock_t *__rwlock); -#endif - -extern int __pthread_key_create (pthread_key_t *__key, - void (*__destr_function) (void *)); - -extern int __pthread_setspecific (pthread_key_t __key, - __const void *__pointer); - -extern void *__pthread_getspecific (pthread_key_t __key); - -extern int __pthread_once (pthread_once_t *__once_control, - void (*__init_routine) (void)); - -extern int __pthread_atfork (void (*__prepare) (void), - void (*__parent) (void), - void (*__child) (void)); - - - -/* Make the pthread functions weak so that we can elide them from - single-threaded processes. */ -#ifndef __NO_WEAK_PTHREAD_ALIASES -# ifdef weak_extern -# if _LIBC -# include -# else -# define BP_SYM (sym) sym -# endif -weak_extern (BP_SYM (__pthread_mutex_init)) -weak_extern (BP_SYM (__pthread_mutex_destroy)) -weak_extern (BP_SYM (__pthread_mutex_lock)) -weak_extern (BP_SYM (__pthread_mutex_trylock)) -weak_extern (BP_SYM (__pthread_mutex_unlock)) -weak_extern (BP_SYM (__pthread_mutexattr_init)) -weak_extern (BP_SYM (__pthread_mutexattr_destroy)) -weak_extern (BP_SYM (__pthread_mutexattr_settype)) -weak_extern (BP_SYM (__pthread_rwlock_init)) -weak_extern (BP_SYM (__pthread_rwlock_destroy)) -weak_extern (BP_SYM (__pthread_rwlock_rdlock)) -weak_extern (BP_SYM (__pthread_rwlock_tryrdlock)) -weak_extern (BP_SYM (__pthread_rwlock_wrlock)) -weak_extern (BP_SYM (__pthread_rwlock_trywrlock)) -weak_extern (BP_SYM (__pthread_rwlock_unlock)) -weak_extern (BP_SYM (__pthread_key_create)) -weak_extern (BP_SYM (__pthread_setspecific)) -weak_extern (BP_SYM (__pthread_getspecific)) -weak_extern (BP_SYM (__pthread_once)) -weak_extern (__pthread_initialize) -weak_extern (__pthread_atfork) -weak_extern (BP_SYM (_pthread_cleanup_push_defer)) -weak_extern (BP_SYM (_pthread_cleanup_pop_restore)) -# else -# pragma weak __pthread_mutex_init -# pragma weak __pthread_mutex_destroy -# pragma weak __pthread_mutex_lock -# pragma weak __pthread_mutex_trylock -# pragma weak __pthread_mutex_unlock -# pragma weak __pthread_mutexattr_init -# pragma weak __pthread_mutexattr_destroy -# pragma weak __pthread_mutexattr_settype -# pragma weak __pthread_rwlock_destroy -# pragma weak __pthread_rwlock_rdlock -# pragma weak __pthread_rwlock_tryrdlock -# pragma weak __pthread_rwlock_wrlock -# pragma weak __pthread_rwlock_trywrlock -# pragma weak __pthread_rwlock_unlock -# pragma weak __pthread_key_create -# pragma weak __pthread_setspecific -# pragma weak __pthread_getspecific -# pragma weak __pthread_once -# pragma weak __pthread_initialize -# pragma weak __pthread_atfork -# pragma weak _pthread_cleanup_push_defer -# pragma weak _pthread_cleanup_pop_restore -# endif -#endif - -/* We need portable names for some functions. E.g., when they are - used as argument to __libc_cleanup_region_start. */ -#define __libc_mutex_unlock __pthread_mutex_unlock - -#endif /* bits/libc-lock.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h b/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h deleted file mode 100644 index efd0c83be..000000000 --- a/libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h +++ /dev/null @@ -1,66 +0,0 @@ -/* libc-internal interface for thread-specific data. LinuxThreads version. - Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _BITS_LIBC_TSD_H -#define _BITS_LIBC_TSD_H 1 - -/* Fast thread-specific data internal to libc. */ -enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0, - _LIBC_TSD_KEY_DL_ERROR, - _LIBC_TSD_KEY_RPC_VARS, - _LIBC_TSD_KEY_LOCALE, - _LIBC_TSD_KEY_CTYPE_B, - _LIBC_TSD_KEY_CTYPE_TOLOWER, - _LIBC_TSD_KEY_CTYPE_TOUPPER, - _LIBC_TSD_KEY_N }; - -#include -#include - -#if USE_TLS && HAVE___THREAD - -/* When __thread works, the generic definition is what we want. */ -# include - -#else - -extern void *(*__libc_internal_tsd_get) (enum __libc_tsd_key_t) __THROW; -extern int (*__libc_internal_tsd_set) (enum __libc_tsd_key_t, - __const void *) __THROW; -extern void **(*const __libc_internal_tsd_address) (enum __libc_tsd_key_t) - __THROW __attribute__ ((__const__)); - -#define __libc_tsd_address(KEY) \ - (__libc_internal_tsd_address != NULL \ - ? __libc_internal_tsd_address (_LIBC_TSD_KEY_##KEY) \ - : &__libc_tsd_##KEY##_data) - -#define __libc_tsd_define(CLASS, KEY) CLASS void *__libc_tsd_##KEY##_data; -#define __libc_tsd_get(KEY) \ - (__libc_internal_tsd_get != NULL \ - ? __libc_internal_tsd_get (_LIBC_TSD_KEY_##KEY) \ - : __libc_tsd_##KEY##_data) -#define __libc_tsd_set(KEY, VALUE) \ - (__libc_internal_tsd_set != NULL \ - ? __libc_internal_tsd_set (_LIBC_TSD_KEY_##KEY, (VALUE)) \ - : ((__libc_tsd_##KEY##_data = (VALUE)), 0)) - -#endif - -#endif /* bits/libc-tsd.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h b/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h deleted file mode 100644 index faec63b06..000000000 --- a/libpthread/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h +++ /dev/null @@ -1,142 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -#if !defined _BITS_TYPES_H && !defined _PTHREAD_H -# error "Never include directly; use instead." -#endif - -#ifndef _BITS_PTHREADTYPES_H -#define _BITS_PTHREADTYPES_H 1 - -#define __need_schedparam -#include - -/* Fast locks (not abstract because mutexes and conditions aren't abstract). */ -struct _pthread_fastlock -{ - long int __status; /* "Free" or "taken" or head of waiting list */ - int __spinlock; /* Used by compare_and_swap emulation. Also, - adaptive SMP lock stores spin count here. */ -}; - -#ifndef _PTHREAD_DESCR_DEFINED -/* Thread descriptors */ -typedef struct _pthread_descr_struct *_pthread_descr; -# define _PTHREAD_DESCR_DEFINED -#endif - - -/* Attributes for threads. */ -typedef struct __pthread_attr_s -{ - int __detachstate; - int __schedpolicy; - struct __sched_param __schedparam; - int __inheritsched; - int __scope; - size_t __guardsize; - int __stackaddr_set; - void *__stackaddr; - size_t __stacksize; -} pthread_attr_t; - - -/* Conditions (not abstract because of PTHREAD_COND_INITIALIZER */ -typedef struct -{ - struct _pthread_fastlock __c_lock; /* Protect against concurrent access */ - _pthread_descr __c_waiting; /* Threads waiting on this condition */ -} pthread_cond_t; - - -/* Attribute for conditionally variables. */ -typedef struct -{ - int __dummy; -} pthread_condattr_t; - -/* Keys for thread-specific data */ -typedef unsigned int pthread_key_t; - - -/* Mutexes (not abstract because of PTHREAD_MUTEX_INITIALIZER). */ -/* (The layout is unnatural to maintain binary compatibility - with earlier releases of LinuxThreads.) */ -typedef struct -{ - int __m_reserved; /* Reserved for future use */ - int __m_count; /* Depth of recursive locking */ - _pthread_descr __m_owner; /* Owner thread (if recursive or errcheck) */ - int __m_kind; /* Mutex kind: fast, recursive or errcheck */ - struct _pthread_fastlock __m_lock; /* Underlying fast lock */ -} pthread_mutex_t; - - -/* Attribute for mutex. */ -typedef struct -{ - int __mutexkind; -} pthread_mutexattr_t; - - -/* Once-only execution */ -typedef int pthread_once_t; - - -#if defined __USE_UNIX98 || defined __USE_XOPEN2K -/* Read-write locks. */ -typedef struct _pthread_rwlock_t -{ - struct _pthread_fastlock __rw_lock; /* Lock to guarantee mutual exclusion */ - int __rw_readers; /* Number of readers */ - _pthread_descr __rw_writer; /* Identity of writer, or NULL if none */ - _pthread_descr __rw_read_waiting; /* Threads waiting for reading */ - _pthread_descr __rw_write_waiting; /* Threads waiting for writing */ - int __rw_kind; /* Reader/Writer preference selection */ - int __rw_pshared; /* Shared between processes or not */ -} pthread_rwlock_t; - - -/* Attribute for read-write locks. */ -typedef struct -{ - int __lockkind; - int __pshared; -} pthread_rwlockattr_t; -#endif - -#ifdef __USE_XOPEN2K -/* POSIX spinlock data type. */ -typedef volatile int pthread_spinlock_t; - -/* POSIX barrier. */ -typedef struct { - struct _pthread_fastlock __ba_lock; /* Lock to guarantee mutual exclusion */ - int __ba_required; /* Threads needed for completion */ - int __ba_present; /* Threads waiting */ - _pthread_descr __ba_waiting; /* Queue of waiting threads */ -} pthread_barrier_t; - -/* barrier attribute */ -typedef struct { - int __pshared; -} pthread_barrierattr_t; - -#endif - - -/* Thread identifiers */ -typedef unsigned long int pthread_t; - -#endif /* bits/pthreadtypes.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/pthread.h b/libpthread/linuxthreads/sysdeps/pthread/pthread.h deleted file mode 100644 index 6613cab88..000000000 --- a/libpthread/linuxthreads/sysdeps/pthread/pthread.h +++ /dev/null @@ -1,705 +0,0 @@ -/* Linuxthreads - a simple clone()-based implementation of Posix */ -/* threads for Linux. */ -/* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ -/* */ -/* This program is free software; you can redistribute it and/or */ -/* modify it under the terms of the GNU Library General Public License */ -/* as published by the Free Software Foundation; either version 2 */ -/* of the License, or (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU Library General Public License for more details. */ - -#ifndef _PTHREAD_H -#define _PTHREAD_H 1 - -#include - -#include -#include - -#define __need_sigset_t -#include -#include -#include -#ifdef _LIBC -#include -#endif - - -__BEGIN_DECLS - -/* Initializers. */ - -#define PTHREAD_MUTEX_INITIALIZER \ - {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER} -#ifdef __USE_GNU -# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ - {0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __LOCK_INITIALIZER} -# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ - {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __LOCK_INITIALIZER} -# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ - {0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __LOCK_INITIALIZER} -#endif - -#define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER, 0} - -#if defined __USE_UNIX98 || defined __USE_XOPEN2K -# define PTHREAD_RWLOCK_INITIALIZER \ - { __LOCK_INITIALIZER, 0, NULL, NULL, NULL, \ - PTHREAD_RWLOCK_DEFAULT_NP, PTHREAD_PROCESS_PRIVATE } -#endif -#ifdef __USE_GNU -# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ - { __LOCK_INITIALIZER, 0, NULL, NULL, NULL, \ - PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, PTHREAD_PROCESS_PRIVATE } -#endif - -/* Values for attributes. */ - -enum -{ - PTHREAD_CREATE_JOINABLE, -#define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_JOINABLE - PTHREAD_CREATE_DETACHED -#define PTHREAD_CREATE_DETACHED PTHREAD_CREATE_DETACHED -}; - -enum -{ - PTHREAD_INHERIT_SCHED, -#define PTHREAD_INHERIT_SCHED PTHREAD_INHERIT_SCHED - PTHREAD_EXPLICIT_SCHED -#define PTHREAD_EXPLICIT_SCHED PTHREAD_EXPLICIT_SCHED -}; - -enum -{ - PTHREAD_SCOPE_SYSTEM, -#define PTHREAD_SCOPE_SYSTEM PTHREAD_SCOPE_SYSTEM - PTHREAD_SCOPE_PROCESS -#define PTHREAD_SCOPE_PROCESS PTHREAD_SCOPE_PROCESS -}; - -enum -{ - PTHREAD_MUTEX_ADAPTIVE_NP, - PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_TIMED_NP -#ifdef __USE_UNIX98 - , - PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_ADAPTIVE_NP, - PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, - PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, - PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL -#endif -#ifdef __USE_GNU - /* For compatibility. */ - , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_ADAPTIVE_NP -#endif -}; - -enum -{ - PTHREAD_PROCESS_PRIVATE, -#define PTHREAD_PROCESS_PRIVATE PTHREAD_PROCESS_PRIVATE - PTHREAD_PROCESS_SHARED -#define PTHREAD_PROCESS_SHARED PTHREAD_PROCESS_SHARED -}; - -#if defined __USE_UNIX98 || defined __USE_XOPEN2K -enum -{ - PTHREAD_RWLOCK_PREFER_READER_NP, - PTHREAD_RWLOCK_PREFER_WRITER_NP, - PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, - PTHREAD_RWLOCK_DEFAULT_NP = PTHREAD_RWLOCK_PREFER_WRITER_NP -}; -#endif /* Unix98 */ - -#define PTHREAD_ONCE_INIT 0 - -/* Special constants */ - -#ifdef __USE_XOPEN2K -/* -1 is distinct from 0 and all errno constants */ -# define PTHREAD_BARRIER_SERIAL_THREAD -1 -#endif - -/* Cleanup buffers */ - -struct _pthread_cleanup_buffer -{ - void (*__routine) (void *); /* Function to call. */ - void *__arg; /* Its argument. */ - int __canceltype; /* Saved cancellation type. */ - struct _pthread_cleanup_buffer *__prev; /* Chaining of cleanup functions. */ -}; - -/* Cancellation */ - -enum -{ - PTHREAD_CANCEL_ENABLE, -#define PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ENABLE - PTHREAD_CANCEL_DISABLE -#define PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_DISABLE -}; -enum -{ - PTHREAD_CANCEL_DEFERRED, -#define PTHREAD_CANCEL_DEFERRED PTHREAD_CANCEL_DEFERRED - PTHREAD_CANCEL_ASYNCHRONOUS -#define PTHREAD_CANCEL_ASYNCHRONOUS PTHREAD_CANCEL_ASYNCHRONOUS -}; -#define PTHREAD_CANCELED ((void *) -1) - - -/* Function for handling threads. */ - -/* Create a thread with given attributes ATTR (or default attributes - if ATTR is NULL), and call function START_ROUTINE with given - arguments ARG. */ -extern int pthread_create (pthread_t *__restrict __threadp, - __const pthread_attr_t *__restrict __attr, - void *(*__start_routine) (void *), - void *__restrict __arg) __THROW; - -/* Obtain the identifier of the current thread. */ -extern pthread_t pthread_self (void) __THROW; - -/* Compare two thread identifiers. */ -extern int pthread_equal (pthread_t __thread1, pthread_t __thread2) __THROW; - -/* Terminate calling thread. */ -extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__)); - -/* Make calling thread wait for termination of the thread TH. The - exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN - is not NULL. */ -extern int pthread_join (pthread_t __th, void **__thread_return); - -/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN. - The resources of TH will therefore be freed immediately when it - terminates, instead of waiting for another thread to perform PTHREAD_JOIN - on it. */ -extern int pthread_detach (pthread_t __th) __THROW; - - -/* Functions for handling attributes. */ - -/* Initialize thread attribute *ATTR with default attributes - (detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, - no user-provided stack). */ -extern int pthread_attr_init (pthread_attr_t *__attr) __THROW; - -/* Destroy thread attribute *ATTR. */ -extern int pthread_attr_destroy (pthread_attr_t *__attr) __THROW; - -/* Set the `detachstate' attribute in *ATTR according to DETACHSTATE. */ -extern int pthread_attr_setdetachstate (pthread_attr_t *__attr, - int __detachstate) __THROW; - -/* Return in *DETACHSTATE the `detachstate' attribute in *ATTR. */ -extern int pthread_attr_getdetachstate (__const pthread_attr_t *__attr, - int *__detachstate) __THROW; - -/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM. */ -extern int pthread_attr_setschedparam (pthread_attr_t *__restrict __attr, - __const struct sched_param *__restrict - __param) __THROW; - -/* Return in *PARAM the scheduling parameters of *ATTR. */ -extern int pthread_attr_getschedparam (__const pthread_attr_t *__restrict - __attr, - struct sched_param *__restrict __param) - __THROW; - -/* Set scheduling policy in *ATTR according to POLICY. */ -extern int pthread_attr_setschedpolicy (pthread_attr_t *__attr, int __policy) - __THROW; - -/* Return in *POLICY the scheduling policy of *ATTR. */ -extern int pthread_attr_getschedpolicy (__const pthread_attr_t *__restrict - __attr, int *__restrict __policy) - __THROW; - -/* Set scheduling inheritance mode in *ATTR according to INHERIT. */ -extern int pthread_attr_setinheritsched (pthread_attr_t *__attr, - int __inherit) __THROW; - -/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */ -extern int pthread_attr_getinheritsched (__const pthread_attr_t *__restrict - __attr, int *__restrict __inherit) - __THROW; - -/* Set scheduling contention scope in *ATTR according to SCOPE. */ -extern int pthread_attr_setscope (pthread_attr_t *__attr, int __scope) - __THROW; - -/* Return in *SCOPE the scheduling contention scope of *ATTR. */ -extern int pthread_attr_getscope (__const pthread_attr_t *__restrict __attr, - int *__restrict __scope) __THROW; - -#ifdef __USE_UNIX98 -/* Set the size of the guard area at the bottom of the thread. */ -extern int pthread_attr_setguardsize (pthread_attr_t *__attr, - size_t __guardsize) __THROW; - -/* Get the size of the guard area at the bottom of the thread. */ -extern int pthread_attr_getguardsize (__const pthread_attr_t *__restrict - __attr, size_t *__restrict __guardsize) - __THROW; -#endif - -/* Set the starting address of the stack of the thread to be created. - Depending on whether the stack grows up or down the value must either - be higher or lower than all the address in the memory block. The - minimal size of the block must be PTHREAD_STACK_SIZE. */ -extern int pthread_attr_setstackaddr (pthread_attr_t *__attr, - void *__stackaddr) __THROW; - -/* Return the previously set address for the stack. */ -extern int pthread_attr_getstackaddr (__const pthread_attr_t *__restrict - __attr, void **__restrict __stackaddr) - __THROW; - -#ifdef __USE_XOPEN2K -/* The following two interfaces are intended to replace the last two. They - require setting the address as well as the size since only setting the - address will make the implementation on some architectures impossible. */ -extern int pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, - size_t __stacksize) __THROW; - -/* Return the previously set address for the stack. */ -extern int pthread_attr_getstack (__const pthread_attr_t *__restrict __attr, - void **__restrict __stackaddr, - size_t *__restrict __stacksize) __THROW; -#endif - -/* Add information about the minimum stack size needed for the thread - to be started. This size must never be less than PTHREAD_STACK_SIZE - and must also not exceed the system limits. */ -extern int pthread_attr_setstacksize (pthread_attr_t *__attr, - size_t __stacksize) __THROW; - -/* Return the currently used minimal stack size. */ -extern int pthread_attr_getstacksize (__const pthread_attr_t *__restrict - __attr, size_t *__restrict __stacksize) - __THROW; - -#if 0 -/* Not yet implemented in uClibc! */ - -#ifdef __USE_GNU -/* Initialize thread attribute *ATTR with attributes corresponding to the - already running thread TH. It shall be called on unitialized ATTR - and destroyed with pthread_attr_destroy when no longer needed. */ -extern int pthread_getattr_np (pthread_t __th, pthread_attr_t *__attr) __THROW; -#endif -#endif - -/* Functions for scheduling control. */ - -/* Set the scheduling parameters for TARGET_THREAD according to POLICY - and *PARAM. */ -extern int pthread_setschedparam (pthread_t __target_thread, int __policy, - __const struct sched_param *__param) - __THROW; - -/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */ -extern int pthread_getschedparam (pthread_t __target_thread, - int *__restrict __policy, - struct sched_param *__restrict __param) - __THROW; - -#ifdef __USE_UNIX98 -/* Determine level of concurrency. */ -extern int pthread_getconcurrency (void) __THROW; - -/* Set new concurrency level to LEVEL. */ -extern int pthread_setconcurrency (int __level) __THROW; -#endif - -#if 0 -/* Not yet implemented in uClibc! */ - -#ifdef __USE_GNU -/* Yield the processor to another thread or process. - This function is similar to the POSIX `sched_yield' function but - might be differently implemented in the case of a m-on-n thread - implementation. */ -extern int pthread_yield (void) __THROW; -#endif -#endif - -/* Functions for mutex handling. */ - -/* Initialize MUTEX using attributes in *MUTEX_ATTR, or use the - default values if later is NULL. */ -extern int pthread_mutex_init (pthread_mutex_t *__restrict __mutex, - __const pthread_mutexattr_t *__restrict - __mutex_attr) __THROW; - -/* Destroy MUTEX. */ -extern int pthread_mutex_destroy (pthread_mutex_t *__mutex) __THROW; - -/* Try to lock MUTEX. */ -extern int pthread_mutex_trylock (pthread_mutex_t *__mutex) __THROW; - -/* Wait until lock for MUTEX becomes available and lock it. */ -extern int pthread_mutex_lock (pthread_mutex_t *__mutex) __THROW; - -#ifdef __USE_XOPEN2K -/* Wait until lock becomes available, or specified time passes. */ -extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex, - __const struct timespec *__restrict - __abstime) __THROW; -#endif - -/* Unlock MUTEX. */ -extern int pthread_mutex_unlock (pthread_mutex_t *__mutex) __THROW; - - -/* Functions for handling mutex attributes. */ - -/* Initialize mutex attribute object ATTR with default attributes - (kind is PTHREAD_MUTEX_TIMED_NP). */ -extern int pthread_mutexattr_init (pthread_mutexattr_t *__attr) __THROW; - -/* Destroy mutex attribute object ATTR. */ -extern int pthread_mutexattr_destroy (pthread_mutexattr_t *__attr) __THROW; - -/* Get the process-shared flag of the mutex attribute ATTR. */ -extern int pthread_mutexattr_getpshared (__const pthread_mutexattr_t * - __restrict __attr, - int *__restrict __pshared) __THROW; - -/* Set the process-shared flag of the mutex attribute ATTR. */ -extern int pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, - int __pshared) __THROW; - -#ifdef __USE_UNIX98 -/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL, - PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or - PTHREAD_MUTEX_DEFAULT). */ -extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind) - __THROW; - -/* Return in *KIND the mutex kind attribute in *ATTR. */ -extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict - __attr, int *__restrict __kind) __THROW; -#endif - - -/* Functions for handling conditional variables. */ - -/* Initialize condition variable COND using attributes ATTR, or use - the default values if later is NULL. */ -extern int pthread_cond_init (pthread_cond_t *__restrict __cond, - __const pthread_condattr_t *__restrict - __cond_attr) __THROW; - -/* Destroy condition variable COND. */ -extern int pthread_cond_destroy (pthread_cond_t *__cond) __THROW; - -/* Wake up one thread waiting for condition variable COND. */ -extern int pthread_cond_signal (pthread_cond_t *__cond) __THROW; - -/* Wake up all threads waiting for condition variables COND. */ -extern int pthread_cond_broadcast (pthread_cond_t *__cond) __THROW; - -/* Wait for condition variable COND to be signaled or broadcast. - MUTEX is assumed to be locked before. */ -extern int pthread_cond_wait (pthread_cond_t *__restrict __cond, - pthread_mutex_t *__restrict __mutex); - -/* Wait for condition variable COND to be signaled or broadcast until - ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an - absolute time specification; zero is the beginning of the epoch - (00:00:00 GMT, January 1, 1970). */ -extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond, - pthread_mutex_t *__restrict __mutex, - __const struct timespec *__restrict - __abstime); - -/* Functions for handling condition variable attributes. */ - -/* Initialize condition variable attribute ATTR. */ -extern int pthread_condattr_init (pthread_condattr_t *__attr) __THROW; - -/* Destroy condition variable attribute ATTR. */ -extern int pthread_condattr_destroy (pthread_condattr_t *__attr) __THROW; - -/* Get the process-shared flag of the condition variable attribute ATTR. */ -extern int pthread_condattr_getpshared (__const pthread_condattr_t * - __restrict __attr, - int *__restrict __pshared) __THROW; - -/* Set the process-shared flag of the condition variable attribute ATTR. */ -extern int pthread_condattr_setpshared (pthread_condattr_t *__attr, - int __pshared) __THROW; - - -#if defined __USE_UNIX98 || defined __USE_XOPEN2K -/* Functions for handling read-write locks. */ - -/* Initialize read-write lock RWLOCK using attributes ATTR, or use - the default values if later is NULL. */ -extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock, - __const pthread_rwlockattr_t *__restrict - __attr) __THROW; - -/* Destroy read-write lock RWLOCK. */ -extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock) __THROW; - -/* Acquire read lock for RWLOCK. */ -extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock) __THROW; - -/* Try to acquire read lock for RWLOCK. */ -extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock) __THROW; - -# ifdef __USE_XOPEN2K -/* Try to acquire read lock for RWLOCK or return after specfied time. */ -extern int pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, - __const struct timespec *__restrict - __abstime) __THROW; -# endif - -/* Acquire write lock for RWLOCK. */ -extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock) __THROW; - -/* Try to acquire write lock for RWLOCK. */ -extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock) __THROW; - -# ifdef __USE_XOPEN2K -/* Try to acquire write lock for RWLOCK or return after specfied time. */ -extern int pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, - __const struct timespec *__restrict - __abstime) __THROW; -# endif - -/* Unlock RWLOCK. */ -extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock) __THROW; - - -/* Functions for handling read-write lock attributes. */ - -/* Initialize attribute object ATTR with default values. */ -extern int pthread_rwlockattr_init (pthread_rwlockattr_t *__attr) __THROW; - -/* Destroy attribute object ATTR. */ -extern int pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr) __THROW; - -/* Return current setting of process-shared attribute of ATTR in PSHARED. */ -extern int pthread_rwlockattr_getpshared (__const pthread_rwlockattr_t * - __restrict __attr, - int *__restrict __pshared) __THROW; - -/* Set process-shared attribute of ATTR to PSHARED. */ -extern int pthread_rwlockattr_setpshared (pthread_rwlockattr_t *__attr, - int __pshared) __THROW; - -/* Return current setting of reader/writer preference. */ -extern int pthread_rwlockattr_getkind_np (__const pthread_rwlockattr_t *__attr, - int *__pref) __THROW; - -/* Set reader/write preference. */ -extern int pthread_rwlockattr_setkind_np (pthread_rwlockattr_t *__attr, - int __pref) __THROW; -#endif - -#if 0 -/* Not yet implemented in uClibc! */ - -#ifdef __USE_XOPEN2K -/* The IEEE Std. 1003.1j-2000 introduces functions to implement - spinlocks. */ - -/* Initialize the spinlock LOCK. If PSHARED is nonzero the spinlock can - be shared between different processes. */ -extern int pthread_spin_init (pthread_spinlock_t *__lock, int __pshared) - __THROW; - -/* Destroy the spinlock LOCK. */ -extern int pthread_spin_destroy (pthread_spinlock_t *__lock) __THROW; - -/* Wait until spinlock LOCK is retrieved. */ -extern int pthread_spin_lock (pthread_spinlock_t *__lock) __THROW; - -/* Try to lock spinlock LOCK. */ -extern int pthread_spin_trylock (pthread_spinlock_t *__lock) __THROW; - -/* Release spinlock LOCK. */ -extern int pthread_spin_unlock (pthread_spinlock_t *__lock) __THROW; - - -/* Barriers are a also a new feature in 1003.1j-2000. */ - -extern int pthread_barrier_init (pthread_barrier_t *__restrict __barrier, - __const pthread_barrierattr_t *__restrict - __attr, unsigned int __count) __THROW; - -extern int pthread_barrier_destroy (pthread_barrier_t *__barrier) __THROW; - -extern int pthread_barrierattr_init (pthread_barrierattr_t *__attr) __THROW; - -extern int pthread_barrierattr_destroy (pthread_barrierattr_t *__attr) __THROW; - -extern int pthread_barrierattr_getpshared (__const pthread_barrierattr_t * - __restrict __attr, - int *__restrict __pshared) __THROW; - -extern int pthread_barrierattr_setpshared (pthread_barrierattr_t *__attr, - int __pshared) __THROW; - -extern int pthread_barrier_wait (pthread_barrier_t *__barrier) __THROW; -#endif -#endif - - -/* Functions for handling thread-specific data. */ - -/* Create a key value identifying a location in the thread-specific - data area. Each thread maintains a distinct thread-specific data - area. DESTR_FUNCTION, if non-NULL, is called with the value - associated to that key when the key is destroyed. - DESTR_FUNCTION is not called if the value associated is NULL when - the key is destroyed. */ -extern int pthread_key_create (pthread_key_t *__key, - void (*__destr_function) (void *)) __THROW; - -/* Destroy KEY. */ -extern int pthread_key_delete (pthread_key_t __key) __THROW; - -/* Store POINTER in the thread-specific data slot identified by KEY. */ -extern int pthread_setspecific (pthread_key_t __key, - __const void *__pointer) __THROW; - -/* Return current value of the thread-specific data slot identified by KEY. */ -extern void *pthread_getspecific (pthread_key_t __key) __THROW; - - -/* Functions for handling initialization. */ - -/* Guarantee that the initialization function INIT_ROUTINE will be called - only once, even if pthread_once is executed several times with the - same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or - extern variable initialized to PTHREAD_ONCE_INIT. - - The initialization functions might throw exception which is why - this function is not marked with __THROW. */ -extern int pthread_once (pthread_once_t *__once_control, - void (*__init_routine) (void)); - - -/* Functions for handling cancellation. */ - -/* Set cancelability state of current thread to STATE, returning old - state in *OLDSTATE if OLDSTATE is not NULL. */ -extern int pthread_setcancelstate (int __state, int *__oldstate); - -/* Set cancellation state of current thread to TYPE, returning the old - type in *OLDTYPE if OLDTYPE is not NULL. */ -extern int pthread_setcanceltype (int __type, int *__oldtype); - -/* Cancel THREAD immediately or at the next possibility. */ -extern int pthread_cancel (pthread_t __cancelthread); - -/* Test for pending cancellation for the current thread and terminate - the thread as per pthread_exit(PTHREAD_CANCELED) if it has been - cancelled. */ -extern void pthread_testcancel (void); - - -/* Install a cleanup handler: ROUTINE will be called with arguments ARG - when the thread is cancelled or calls pthread_exit. ROUTINE will also - be called with arguments ARG when the matching pthread_cleanup_pop - is executed with non-zero EXECUTE argument. - pthread_cleanup_push and pthread_cleanup_pop are macros and must always - be used in matching pairs at the same nesting level of braces. */ - -#define pthread_cleanup_push(routine,arg) \ - { struct _pthread_cleanup_buffer _buffer; \ - _pthread_cleanup_push (&_buffer, (routine), (arg)); - -extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, - void (*__routine) (void *), - void *__arg) __THROW; - -/* Remove a cleanup handler installed by the matching pthread_cleanup_push. - If EXECUTE is non-zero, the handler function is called. */ - -#define pthread_cleanup_pop(execute) \ - _pthread_cleanup_pop (&_buffer, (execute)); } - -extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, - int __execute) __THROW; - -/* Install a cleanup handler as pthread_cleanup_push does, but also - saves the current cancellation type and set it to deferred cancellation. */ - -#ifdef __USE_GNU -# define pthread_cleanup_push_defer_np(routine,arg) \ - { struct _pthread_cleanup_buffer _buffer; \ - _pthread_cleanup_push_defer (&_buffer, (routine), (arg)); - -extern void _pthread_cleanup_push_defer (struct _pthread_cleanup_buffer *__buffer, - void (*__routine) (void *), - void *__arg) __THROW; - -/* Remove a cleanup handler as pthread_cleanup_pop does, but also - restores the cancellation type that was in effect when the matching - pthread_cleanup_push_defer was called. */ - -# define pthread_cleanup_pop_restore_np(execute) \ - _pthread_cleanup_pop_restore (&_buffer, (execute)); } - -extern void _pthread_cleanup_pop_restore (struct _pthread_cleanup_buffer *__buffer, - int __execute) __THROW; -#endif - - -#if 0 -/* Not yet implemented in uClibc! */ - -#ifdef __USE_XOPEN2K -/* Get ID of CPU-time clock for thread THREAD_ID. */ -extern int pthread_getcpuclockid (pthread_t __thread_id, - clockid_t *__clock_id) __THROW; -#endif -#endif - - -/* Functions for handling signals. */ -#include - - -/* Functions for handling process creation and process execution. */ - -/* Install handlers to be called when a new process is created with FORK. - The PREPARE handler is called in the parent process just before performing - FORK. The PARENT handler is called in the parent process just after FORK. - The CHILD handler is called in the child process. Each of the three - handlers can be NULL, meaning that no handler needs to be called at that - point. - PTHREAD_ATFORK can be called several times, in which case the PREPARE - handlers are called in LIFO order (last added with PTHREAD_ATFORK, - first called before FORK), and the PARENT and CHILD handlers are called - in FIFO (first added, first called). */ - -extern int pthread_atfork (void (*__prepare) (void), - void (*__parent) (void), - void (*__child) (void)) __THROW; - -/* Terminate all threads in the program except the calling process. - Should be called just before invoking one of the exec*() functions. */ - -extern void pthread_kill_other_threads_np (void) __THROW; - -__END_DECLS - -#endif /* pthread.h */ diff --git a/libpthread/linuxthreads/sysdeps/pthread/tls.h b/libpthread/linuxthreads/sysdeps/pthread/tls.h deleted file mode 100644 index 6a23ec05e..000000000 --- a/libpthread/linuxthreads/sysdeps/pthread/tls.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Definition for thread-local data handling. Generic version. - Copyright (C) 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -/* By default no TLS support is available. This is signaled by the - absence of the symbol USE_TLS. */ -#undef USE_TLS - - -/* An architecture-specific version of this file has to defined a - number of symbols: - - TLS_TCB_AT_TP or TLS_DTV_AT_TP - - The presence of one of these symbols signals which variant of - the TLS ABI is used. There are in the moment two variants - available: - - * the thread pointer points to a thread control block - - * the thread pointer points to the dynamic thread vector - - - TLS_TCB_SIZE - - This is the size of the thread control block structure. How - this is actually defined depends on the ABI. The thread control - block could be internal descriptor of the thread library or - just a data structure which allows finding the DTV. - - TLS_INIT_TCB_SIZE - - Similarly, but this value is only used at startup and in the - dynamic linker itself. There are no threads in use at that time. - - - TLS_TCB_ALIGN - - Alignment requirements for the TCB structure. - - TLS_INIT_TCB_ALIGN - - Similarly, but for the structure used at startup time. - - - INSTALL_DTV(tcb, init_dtv) - - This macro must install the given initial DTV into the thread control - block TCB. The normal runtime functionality must then be able to - use the value. - - - TLS_INIT_TP(tcb, firstcall) - - This macro must initialize the thread pointer to enable normal TLS - operation. The first parameter is a pointer to the thread control - block. The second parameter specifies whether this is the first - call for the TCB. ld.so calls this macro more than once. - - - THREAD_DTV() - - This macro returns the address of the DTV of the current thread. - This normally is done using the the thread register which points - to the dtv or the TCB (from which the DTV can found). - */ diff --git a/libpthread/linuxthreads/sysdeps/sh/pt-machine.h b/libpthread/linuxthreads/sysdeps/sh/pt-machine.h deleted file mode 100644 index 02545e6b4..000000000 --- a/libpthread/linuxthreads/sysdeps/sh/pt-machine.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - SuperH version. - Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Niibe Yutaka . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef __ASSEMBLER__ -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - int ret; - - __asm__ __volatile__( - "tas.b @%1\n\t" - "movt %0" - : "=r" (ret) - : "r" (spinlock) - : "memory", "cc"); - - return (ret == 0); -} - -/* We want the OS to assign stack addresses. */ -#define FLOATING_STACKS 1 - -/* Maximum size of the stack if the rlimit is unlimited. */ -#define ARCH_STACK_MAX_SIZE 32*1024*1024 - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("r15"); - -/* Return the thread descriptor for the current thread. */ -struct _pthread_descr_struct; -#define THREAD_SELF \ - ({ struct _pthread_descr_struct *self; \ - __asm__("stc gbr,%0" : "=r" (self)); self;}) - -/* Initialize the thread-unique value. */ -#define INIT_THREAD_SELF(descr, nr) \ - ({ __asm__ __volatile__("ldc %0,gbr" : : "r" (descr));}) - -/* Access to data in the thread descriptor is easy. */ -#define THREAD_GETMEM(descr, member) \ - ((void) sizeof (descr), THREAD_SELF->member) -#define THREAD_GETMEM_NC(descr, member) \ - ((void) sizeof (descr), THREAD_SELF->member) -#define THREAD_SETMEM(descr, member, value) \ - ((void) sizeof (descr), THREAD_SELF->member = (value)) -#define THREAD_SETMEM_NC(descr, member, value) \ - ((void) sizeof (descr), THREAD_SELF->member = (value)) -#endif /* __ASSEMBLER__ */ - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/sh/tls.h b/libpthread/linuxthreads/sysdeps/sh/tls.h deleted file mode 100644 index 75326d8e1..000000000 --- a/libpthread/linuxthreads/sysdeps/sh/tls.h +++ /dev/null @@ -1,117 +0,0 @@ -/* Definition for thread-local data handling. linuxthreads/SH version. - Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _TLS_H -#define _TLS_H - -# include - -#ifndef __ASSEMBLER__ -# include -# include -# include - -/* Type for the dtv. */ -typedef union dtv -{ - size_t counter; - void *pointer; -} dtv_t; - - -typedef struct -{ - void *tcb; /* Pointer to the TCB. Not necessary the - thread descriptor used by libpthread. */ - dtv_t *dtv; - void *self; /* Pointer to the thread descriptor. */ -} tcbhead_t; - - -/* We can support TLS only if the floating-stack support is available. */ -#if defined FLOATING_STACKS && defined HAVE_TLS_SUPPORT - -/* Get system call information. */ -# include - -/* Signal that TLS support is available. */ -//# define USE_TLS 1 - - -/* Get the thread descriptor definition. */ -# include - -/* This is the size of the initial TCB. */ -# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) - -/* Alignment requirements for the initial TCB. */ -# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) - -/* This is the size of the TCB. */ -# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) - -/* Alignment requirements for the TCB. */ -# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) - -/* The TLS blocks start right after the TCB. */ -# define TLS_DTV_AT_TP 1 - - -/* Install the dtv pointer. The pointer passed is to the element with - index -1 which contain the length. */ -# define INSTALL_DTV(descr, dtvp) \ - ((tcbhead_t *) (descr))->dtv = dtvp + 1 - -/* Install new dtv for current thread. */ -# define INSTALL_NEW_DTV(dtv) \ - ({ struct _pthread_descr_struct *__descr; \ - THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); }) - -/* Return dtv of given thread descriptor. */ -# define GET_DTV(descr) \ - (((tcbhead_t *) (descr))->dtv) - -/* Code to initially initialize the thread pointer. This might need - special attention since 'errno' is not yet available and if the - operation can cause a failure 'errno' must not be touched. */ -# define TLS_INIT_TP(descr, secondcall) \ - ({ \ - void *_descr = (descr); \ - int result; \ - tcbhead_t *head = _descr; \ - \ - head->tcb = _descr; \ - /* For now the thread descriptor is at the same address. */ \ - head->self = _descr; \ - \ - asm ("ldc %0,gbr" : : "r" (_descr)); \ - \ - 0; \ - }) - - -/* Return the address of the dtv for the current thread. */ -# define THREAD_DTV() \ - ({ struct _pthread_descr_struct *__descr; \ - THREAD_GETMEM (__descr, p_header.data.dtvp); }) - -#endif /* FLOATING_STACKS && HAVE_TLS_SUPPORT */ -#endif /* __ASSEMBLER__ */ - -#endif /* tls.h */ diff --git a/libpthread/linuxthreads/sysdeps/sh64/Makefile.arch b/libpthread/linuxthreads/sysdeps/sh64/Makefile.arch deleted file mode 100644 index 38cd12db6..000000000 --- a/libpthread/linuxthreads/sysdeps/sh64/Makefile.arch +++ /dev/null @@ -1,26 +0,0 @@ -# Makefile for uClibc -# -# Copyright (C) 2003 Paul Mundt -# Copyright (C) 2000-2005 Erik Andersen -# -# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. -# - -# We need to build as SHcompact for tas.. -ARCH_CFLAGS:=$(subst 32media,compact,$(ARCH_CFLAGS)) - -libpthread_ARCH_DIR:=$(top_srcdir)libpthread/linuxthreads/sysdeps/sh64 -libpthread_ARCH_OUT:=$(top_builddir)libpthread/linuxthreads/sysdeps/sh64 - -libpthread_ARCH_SRC:=$(wildcard $(libpthread_ARCH_DIR)/*.c) -libpthread_ARCH_OBJ:=$(patsubst $(libpthread_ARCH_DIR)/%.c,$(libpthread_ARCH_OUT)/%.o,$(libpthread_ARCH_SRC)) - -libpthread-a-$(UCLIBC_HAS_THREADS)+=$(libpthread_ARCH_OBJ) -libpthread-so-$(UCLIBC_HAS_THREADS)+=$(libpthread_ARCH_OBJ:.o=.os) - -libpthread-multi-$(UCLIBC_HAS_THREADS)+=$(libpthread_ARCH_SRC) - -objclean-y+=libpthread_arch_objclean - -libpthread_arch_objclean: - $(RM) $(libpthread_ARCH_OUT)/*.{o,os} diff --git a/libpthread/linuxthreads/sysdeps/sh64/pt-machine.c b/libpthread/linuxthreads/sysdeps/sh64/pt-machine.c deleted file mode 100644 index ea4881322..000000000 --- a/libpthread/linuxthreads/sysdeps/sh64/pt-machine.c +++ /dev/null @@ -1,47 +0,0 @@ -/* Cloned for uClibc by Paul Mundt, December 2003 */ -/* Modified by SuperH, Inc. September 2003 */ - -/* Machine-dependent pthreads configuration and inline functions. - SH5 version. - Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Niibe Yutaka . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include "pt-machine.h" - -/* Spinlock implementation; required. */ - -/* The SH5 does not have a suitable test-and-set instruction (SWAP only - operates on an aligned quad word). So we use the SH4 version instead. - This must be seperately compiled in SHcompact mode, so it cannot be - inline. */ - -long int testandset (int *spinlock) -{ - int ret; - - __asm__ __volatile__( - "tas.b @%1\n\t" - "movt %0" - : "=r" (ret) - : "r" (spinlock) - : "memory", "cc"); - - return (ret == 0); -} - diff --git a/libpthread/linuxthreads/sysdeps/sh64/pt-machine.h b/libpthread/linuxthreads/sysdeps/sh64/pt-machine.h deleted file mode 100644 index 8269a4cb3..000000000 --- a/libpthread/linuxthreads/sysdeps/sh64/pt-machine.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Cloned for uClibc by Paul Mundt, December 2003 */ -/* Modified by SuperH, Inc. September 2003 */ - -/* Machine-dependent pthreads configuration and inline functions. - SuperH version. - Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Niibe Yutaka . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef PT_EI -# define PT_EI extern inline -#endif - -/* Spinlock implementation; required. */ -extern long int testandset (int *spinlock); - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("r15"); diff --git a/libpthread/linuxthreads/sysdeps/sparc/pt-machine.h b/libpthread/linuxthreads/sysdeps/sparc/pt-machine.h deleted file mode 100644 index ab90810f1..000000000 --- a/libpthread/linuxthreads/sysdeps/sparc/pt-machine.h +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -#if __WORDSIZE == 32 -# include "sparc32/pt-machine.h" -#else -# include "sparc64/pt-machine.h" -#endif diff --git a/libpthread/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h b/libpthread/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h deleted file mode 100644 index 322a52051..000000000 --- a/libpthread/linuxthreads/sysdeps/sparc/sparc32/pt-machine.h +++ /dev/null @@ -1,83 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - sparc version. - Copyright (C) 1996-1998, 2000-2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - int ret; - - __asm__ __volatile__("ldstub %1,%0" - : "=r"(ret), "=m"(*spinlock) - : "m"(*spinlock)); - - return ret; -} - - -/* Memory barrier; default is to do nothing */ -#define MEMORY_BARRIER() __asm__ __volatile__("stbar" : : : "memory") - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME (stack_pointer + (2 * 64)) -register char *stack_pointer __asm__("%sp"); - - -/* Registers %g6 and %g7 are reserved by the ABI for "system use". - %g7 is specified in the TLS ABI as thread pointer -- we do the same. */ -struct _pthread_descr_struct; -register struct _pthread_descr_struct *__thread_self __asm__("%g7"); - -/* Return the thread descriptor for the current thread. */ -#define THREAD_SELF __thread_self - -/* Initialize the thread-unique value. */ -#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) - -/* Access to data in the thread descriptor is easy. */ -#define THREAD_GETMEM(descr, member) \ - ((void) sizeof (descr), THREAD_SELF->member) -#define THREAD_GETMEM_NC(descr, member) \ - ((void) sizeof (descr), THREAD_SELF->member) -#define THREAD_SETMEM(descr, member, value) \ - ((void) sizeof (descr), THREAD_SELF->member = (value)) -#define THREAD_SETMEM_NC(descr, member, value) \ - ((void) sizeof (descr), THREAD_SELF->member = (value)) - -/* We want the OS to assign stack addresses. */ -#define FLOATING_STACKS 1 - -/* Maximum size of the stack if the rlimit is unlimited. */ -#define ARCH_STACK_MAX_SIZE 8*1024*1024 - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h b/libpthread/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h deleted file mode 100644 index f65c13be1..000000000 --- a/libpthread/linuxthreads/sysdeps/sparc/sparc64/pt-machine.h +++ /dev/null @@ -1,105 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - Sparc v9 version. - Copyright (C) 1997-2002, 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson . - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -#endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - int ret; - - __asm__ __volatile__("ldstub %1,%0" - : "=r" (ret), "=m" (*spinlock) : "m" (*spinlock)); - - return ret; -} - - -/* Memory barrier; default is to do nothing */ -#define MEMORY_BARRIER() \ - __asm__ __volatile__("membar #LoadLoad | #LoadStore | #StoreLoad | #StoreStore" : : : "memory") -/* Read barrier. */ -#define READ_MEMORY_BARRIER() \ - __asm__ __volatile__("membar #LoadLoad | #LoadStore" : : : "memory") -/* Write barrier. */ -#define WRITE_MEMORY_BARRIER() \ - __asm__ __volatile__("membar #StoreLoad | #StoreStore" : : : "memory") - - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME (stack_pointer + (2 * 128)) -register char *stack_pointer __asm__ ("%sp"); - - -/* Registers %g6 and %g7 are reserved by the ABI for "system use". The - TLS ABI specifies %g7 as the thread pointer. */ -struct _pthread_descr_struct; -register struct _pthread_descr_struct *__thread_self __asm__ ("%g7"); - -/* Return the thread descriptor for the current thread. */ -#define THREAD_SELF __thread_self - -/* Initialize the thread-unique value. */ -#define INIT_THREAD_SELF(descr, nr) (__thread_self = (descr)) - - -/* Compare-and-swap for semaphores. */ - -#define HAS_COMPARE_AND_SWAP -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - long int readval; - - __asm__ __volatile__ ("casx [%4], %2, %0" - : "=r"(readval), "=m"(*p) - : "r"(oldval), "m"(*p), "r"(p), "0"(newval)); - MEMORY_BARRIER(); - return readval == oldval; -} - -/* Access to data in the thread descriptor is easy. */ -#define THREAD_GETMEM(descr, member) \ - ((void) sizeof (descr), THREAD_SELF->member) -#define THREAD_GETMEM_NC(descr, member) \ - ((void) sizeof (descr), THREAD_SELF->member) -#define THREAD_SETMEM(descr, member, value) \ - ((void) sizeof (descr), THREAD_SELF->member = (value)) -#define THREAD_SETMEM_NC(descr, member, value) \ - ((void) sizeof (descr), THREAD_SELF->member = (value)) - -/* We want the OS to assign stack addresses. */ -#define FLOATING_STACKS 1 - -/* Maximum size of the stack if the rlimit is unlimited. */ -#define ARCH_STACK_MAX_SIZE 32*1024*1024 - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/v850/pt-machine.h b/libpthread/linuxthreads/sysdeps/v850/pt-machine.h deleted file mode 100644 index fb41c41e9..000000000 --- a/libpthread/linuxthreads/sysdeps/v850/pt-machine.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * sysdeps/v850/pt-machine.h -- v850-specific pthread definitions - * - * Copyright (C) 2002 NEC Electronics Corporation - * Copyright (C) 2002 Miles Bader - * - * This file is subject to the terms and conditions of the GNU Lesser - * General Public License. See the file COPYING.LIB in the main - * directory of this archive for more details. - * - * Written by Miles Bader - */ - -#ifndef PT_EI -# define PT_EI extern inline -#endif - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -#define CURRENT_STACK_FRAME __stack_pointer -register char *__stack_pointer __asm__ ("sp"); - -#define HAS_COMPARE_AND_SWAP - -/* Atomically: If *PTR == OLD, set *PTR to NEW and return true, - otherwise do nothing and return false. */ -PT_EI int -__compare_and_swap (long *ptr, long old, long new) -{ - unsigned long psw; - - /* disable interrupts */ - __asm__ __volatile__ ("stsr psw, %0; di" : "=&r" (psw)); - - if (likely (*ptr == old)) - { - *ptr = new; - __asm__ __volatile__ ("ldsr %0, psw" :: "r" (psw)); /* re-enable */ - return 1; - } - else - { - __asm__ __volatile__ ("ldsr %0, psw" :: "r" (psw)); /* re-enable */ - return 0; - } -} diff --git a/libpthread/linuxthreads/sysdeps/x86_64/pt-machine.h b/libpthread/linuxthreads/sysdeps/x86_64/pt-machine.h deleted file mode 100644 index 8a2d1a762..000000000 --- a/libpthread/linuxthreads/sysdeps/x86_64/pt-machine.h +++ /dev/null @@ -1,86 +0,0 @@ -/* Machine-dependent pthreads configuration and inline functions. - x86-64 version. - Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _PT_MACHINE_H -#define _PT_MACHINE_H 1 - -#ifndef __ASSEMBLER__ -# include /* For offsetof. */ -# include /* For abort(). */ -# include - - -# ifndef PT_EI -# define PT_EI extern inline __attribute__ ((always_inline)) -# endif - -extern long int testandset (int *spinlock); -extern int __compare_and_swap (long int *p, long int oldval, long int newval); - -/* Get some notion of the current stack. Need not be exactly the top - of the stack, just something somewhere in the current frame. */ -# define CURRENT_STACK_FRAME stack_pointer -register char * stack_pointer __asm__ ("%rsp") __attribute_used__; - - -/* Spinlock implementation; required. */ -PT_EI long int -testandset (int *spinlock) -{ - long int ret; - - __asm__ __volatile__ ( - "xchgl %k0, %1" - : "=r"(ret), "=m"(*spinlock) - : "0"(1), "m"(*spinlock) - : "memory"); - - return ret; -} - - -/* Compare-and-swap for semaphores. */ -# define HAS_COMPARE_AND_SWAP - -PT_EI int -__compare_and_swap (long int *p, long int oldval, long int newval) -{ - char ret; - long int readval; - - __asm__ __volatile__ ("lock; cmpxchgq %3, %1; sete %0" - : "=q" (ret), "=m" (*p), "=a" (readval) - : "r" (newval), "m" (*p), "a" (oldval) - : "memory"); - return ret; -} - -#endif /* !__ASSEMBLER__ */ - -/* We want the OS to assign stack addresses. */ -#define FLOATING_STACKS 1 - -/* Maximum size of the stack if the rlimit is unlimited. */ -#define ARCH_STACK_MAX_SIZE 32*1024*1024 - -/* The ia32e really want some help to prevent overheating. */ -#define BUSY_WAIT_NOP __asm__ ("rep; nop") - -#endif /* pt-machine.h */ diff --git a/libpthread/linuxthreads/sysdeps/x86_64/tls.h b/libpthread/linuxthreads/sysdeps/x86_64/tls.h deleted file mode 100644 index d67275c10..000000000 --- a/libpthread/linuxthreads/sysdeps/x86_64/tls.h +++ /dev/null @@ -1,134 +0,0 @@ -/* Definitions for thread-local data handling. linuxthreads/x86-64 version. - Copyright (C) 2002, 2005 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _TLS_H -#define _TLS_H - -#ifndef __ASSEMBLER__ - -# include -# include -# include - -/* Type for the dtv. */ -typedef union dtv -{ - size_t counter; - struct - { - void *val; - bool is_static; - } pointer; -} dtv_t; - - -typedef struct -{ - void *tcb; /* Pointer to the TCB. Not necessary the - thread descriptor used by libpthread. */ - dtv_t *dtv; - void *self; /* Pointer to the thread descriptor. */ - int multiple_threads; -} tcbhead_t; - -#else /* __ASSEMBLER__ */ -# include -#endif - - -#ifdef HAVE_TLS_SUPPORT - -/* Signal that TLS support is available. */ -# define USE_TLS 1 - -# ifndef __ASSEMBLER__ -/* Get system call information. */ -# include - -/* Get the thread descriptor definition. */ -# include - -/* This is the size of the initial TCB. */ -# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t) - -/* Alignment requirements for the initial TCB. */ -# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t) - -/* This is the size of the TCB. */ -# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct) - -/* Alignment requirements for the TCB. */ -# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct) - -/* The TCB can have any size and the memory following the address the - thread pointer points to is unspecified. Allocate the TCB there. */ -# define TLS_TCB_AT_TP 1 - - -/* Install the dtv pointer. The pointer passed is to the element with - index -1 which contain the length. */ -# define INSTALL_DTV(descr, dtvp) \ - ((tcbhead_t *) (descr))->dtv = (dtvp) + 1 - -/* Install new dtv for current thread. */ -# define INSTALL_NEW_DTV(dtv) \ - ({ struct _pthread_descr_struct *__descr; \ - THREAD_SETMEM (__descr, p_header.data.dtvp, (dtv)); }) - -/* Return dtv of given thread descriptor. */ -# define GET_DTV(descr) \ - (((tcbhead_t *) (descr))->dtv) - -/* Code to initially initialize the thread pointer. This might need - special attention since 'errno' is not yet available and if the - operation can cause a failure 'errno' must not be touched. */ -# define TLS_INIT_TP(descr, secondcall) \ - ({ \ - void *_descr = (descr); \ - tcbhead_t *head = _descr; \ - long int _result; \ - \ - head->tcb = _descr; \ - /* For now the thread descriptor is at the same address. */ \ - head->self = _descr; \ - \ - asm volatile ("syscall" \ - : "=a" (_result) \ - : "0" ((unsigned long int) __NR_arch_prctl), \ - "D" ((unsigned long int) ARCH_SET_FS), \ - "S" (_descr) \ - : "memory", "cc", "r11", "cx"); \ - \ - _result ? "cannot set %fs base address for thread-local storage" : 0; \ - }) - -/* Indicate that dynamic linker shouldn't try to initialize TLS even - when no PT_TLS segments are found in the program and libraries - it is linked against. */ -# define TLS_INIT_TP_EXPENSIVE 1 - -/* Return the address of the dtv for the current thread. */ -# define THREAD_DTV() \ - ({ struct _pthread_descr_struct *__descr; \ - THREAD_GETMEM (__descr, p_header.data.dtvp); }) - -# endif /* HAVE_TLS_SUPPORT */ -#endif /* __ASSEMBLER__ */ - -#endif /* tls.h */ diff --git a/libpthread/linuxthreads/wrapsyscall.c b/libpthread/linuxthreads/wrapsyscall.c deleted file mode 100644 index 6b8a00bb5..000000000 --- a/libpthread/linuxthreads/wrapsyscall.c +++ /dev/null @@ -1,220 +0,0 @@ -/* Wrapper arpund system calls to provide cancelation points. - Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1996. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#define __FORCE_GLIBC -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifndef __PIC__ -/* We need a hook to force this file to be linked in when static - libpthread is used. */ -const int __pthread_provide_wrappers = 0; -#endif - - -#define CANCELABLE_SYSCALL(res_type, name, param_list, params) \ -res_type __libc_##name param_list; \ -res_type \ -__attribute__ ((weak)) \ -name param_list \ -{ \ - res_type result; \ - int oldtype; \ - pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); \ - result = __libc_##name params; \ - pthread_setcanceltype (oldtype, NULL); \ - return result; \ -} - -#define CANCELABLE_SYSCALL_VA(res_type, name, param_list, params, last_arg) \ -res_type __libc_##name param_list; \ -res_type \ -__attribute__ ((weak)) \ -name param_list \ -{ \ - res_type result; \ - int oldtype; \ - va_list ap; \ - pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); \ - va_start (ap, last_arg); \ - result = __libc_##name params; \ - va_end (ap); \ - pthread_setcanceltype (oldtype, NULL); \ - return result; \ -} - - -/* close(2). */ -CANCELABLE_SYSCALL (int, close, (int fd), (fd)) - - -/* fcntl(2). */ -CANCELABLE_SYSCALL_VA (int, fcntl, (int fd, int cmd, ...), - (fd, cmd, va_arg (ap, long int)), cmd) - - -/* fsync(2). */ -CANCELABLE_SYSCALL (int, fsync, (int fd), (fd)) - - -/* lseek(2). */ -CANCELABLE_SYSCALL (off_t, lseek, (int fd, off_t offset, int whence), - (fd, offset, whence)) - -#ifdef __UCLIBC_HAS_LFS__ -/* lseek64(2). */ -CANCELABLE_SYSCALL (off64_t, lseek64, (int fd, off64_t offset, int whence), - (fd, offset, whence)) -#endif - -/* msync(2). */ -CANCELABLE_SYSCALL (int, msync, (__ptr_t addr, size_t length, int flags), - (addr, length, flags)) - - -/* nanosleep(2). */ -CANCELABLE_SYSCALL (int, nanosleep, (const struct timespec *requested_time, - struct timespec *remaining), - (requested_time, remaining)) - - -/* open(2). */ -CANCELABLE_SYSCALL_VA (int, open, (const char *pathname, int flags, ...), - (pathname, flags, va_arg (ap, mode_t)), flags) - - -#ifdef __UCLIBC_HAS_LFS__ -/* open64(3). */ -CANCELABLE_SYSCALL_VA (int, open64, (const char *pathname, int flags, ...), - (pathname, flags, va_arg (ap, mode_t)), flags) -#endif - -/* pause(2). */ -CANCELABLE_SYSCALL (int, pause, (void), ()) - - -/* Enable this if enabling these in syscalls.c */ -/* pread(3). */ -CANCELABLE_SYSCALL (ssize_t, pread, (int fd, void *buf, size_t count, - off_t offset), - (fd, buf, count, offset)) - - -#if defined __UCLIBC_HAS_LFS__ && defined __NR_pread64 -/* pread64(3). */ -CANCELABLE_SYSCALL (ssize_t, pread64, (int fd, void *buf, size_t count, - off64_t offset), - (fd, buf, count, offset)) -#endif - -/* pwrite(3). */ -CANCELABLE_SYSCALL (ssize_t, pwrite, (int fd, const void *buf, size_t n, - off_t offset), - (fd, buf, n, offset)) - - -#if defined __UCLIBC_HAS_LFS__ && defined __NR_pwrited64 -/* pwrite64(3). */ -CANCELABLE_SYSCALL (ssize_t, pwrite64, (int fd, const void *buf, size_t n, - off64_t offset), - (fd, buf, n, offset)) -#endif - -/* read(2). */ -CANCELABLE_SYSCALL (ssize_t, read, (int fd, void *buf, size_t count), - (fd, buf, count)) - - -/* system(3). */ -CANCELABLE_SYSCALL (int, system, (const char *line), (line)) - - -/* tcdrain(2). */ -CANCELABLE_SYSCALL (int, tcdrain, (int fd), (fd)) - - -/* wait(2). */ -CANCELABLE_SYSCALL (__pid_t, wait, (__WAIT_STATUS_DEFN stat_loc), (stat_loc)) - - -/* waitpid(2). */ -CANCELABLE_SYSCALL (__pid_t, waitpid, (__pid_t pid, int *stat_loc, - int options), - (pid, stat_loc, options)) - - -/* write(2). */ -CANCELABLE_SYSCALL (ssize_t, write, (int fd, const void *buf, size_t n), - (fd, buf, n)) - - -/* The following system calls are thread cancellation points specified - in XNS. */ - -/* accept(2). */ -CANCELABLE_SYSCALL (int, accept, (int fd, __SOCKADDR_ARG addr, - socklen_t *addr_len), - (fd, addr, addr_len)) - -/* connect(2). */ -CANCELABLE_SYSCALL (int, connect, (int fd, __CONST_SOCKADDR_ARG addr, - socklen_t len), - (fd, addr, len)) - -/* recv(2). */ -CANCELABLE_SYSCALL (ssize_t, recv, (int fd, __ptr_t buf, size_t n, int flags), - (fd, buf, n, flags)) - -/* recvfrom(2). */ -CANCELABLE_SYSCALL (ssize_t, recvfrom, (int fd, __ptr_t buf, size_t n, int flags, - __SOCKADDR_ARG addr, socklen_t *addr_len), - (fd, buf, n, flags, addr, addr_len)) - -/* recvmsg(2). */ -CANCELABLE_SYSCALL (ssize_t, recvmsg, (int fd, struct msghdr *message, int flags), - (fd, message, flags)) - -/* send(2). */ -CANCELABLE_SYSCALL (ssize_t, send, (int fd, const __ptr_t buf, size_t n, - int flags), - (fd, buf, n, flags)) - -/* sendmsg(2). */ -CANCELABLE_SYSCALL (ssize_t, sendmsg, (int fd, const struct msghdr *message, - int flags), - (fd, message, flags)) - -/* sendto(2). */ -CANCELABLE_SYSCALL (ssize_t, sendto, (int fd, const __ptr_t buf, size_t n, - int flags, __CONST_SOCKADDR_ARG addr, - socklen_t addr_len), - (fd, buf, n, flags, addr, addr_len)) diff --git a/libpthread/linuxthreads_db/Banner b/libpthread/linuxthreads_db/Banner deleted file mode 100644 index 6f4f3f818..000000000 --- a/libpthread/linuxthreads_db/Banner +++ /dev/null @@ -1 +0,0 @@ -libthread_db work sponsored by Alpha Processor Inc diff --git a/libpthread/linuxthreads_db/Makefile b/libpthread/linuxthreads_db/Makefile deleted file mode 100644 index f92f205a5..000000000 --- a/libpthread/linuxthreads_db/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# Makefile for uClibc -# -# Copyright (C) 2000-2005 Erik Andersen -# -# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. -# - -TOPDIR=../../ - -top_srcdir=$(TOPDIR) -top_builddir=../../ -include $(top_builddir)Rules.mak -all: libs -include Makefile.in -include $(top_srcdir)Makerules diff --git a/libpthread/linuxthreads_db/Makefile.in b/libpthread/linuxthreads_db/Makefile.in deleted file mode 100644 index a066edd0e..000000000 --- a/libpthread/linuxthreads_db/Makefile.in +++ /dev/null @@ -1,43 +0,0 @@ -# Makefile for uClibc -# -# Copyright (C) 2000-2005 Erik Andersen -# -# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. -# - -#CFLAGS+=$(SSP_ALL_CFLAGS) - -PT_MAJOR_VERSION:=$(MAJOR_VERSION) -# Get the thread include dependencies and shared object name -CFLAGS+=-DLIBPTHREAD_SO="\"libpthread.so.$(PT_MAJOR_VERSION)\"" - -# Remove any -z defs since this lib will have undefined symbols -LDFLAGS:=$(subst -z defs,,$(LDFLAGS)) --warn-unresolved-symbols - -ifeq ($(PTHREADS_DEBUG_SUPPORT),y) -STRIP_FLAGS:=-X --strip-debug -R .note -R .comment -endif - -DOMULTI=n - -LIB_NAME:=libthread_db -libthread_db_FULL_NAME:=$(LIB_NAME)-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBLEVEL).so - -MAJOR_VERSION:=1 - -libthread_db_DIR:=$(top_srcdir)libpthread/linuxthreads_db -libthread_db_OUT:=$(top_builddir)libpthread/linuxthreads_db - -libthread_db_SRC:=$(wildcard $(libthread_db_DIR)/*.c) - -libthread_db_OBJ:=$(patsubst $(libthread_db_DIR)/%.c,$(libthread_db_OUT)/%.o,$(libthread_db_SRC)) - -libthread_db-a-$(PTHREADS_DEBUG_SUPPORT)+=$(libthread_db_OBJ) -libthread_db-so-$(PTHREADS_DEBUG_SUPPORT)+=$(libthread_db_OBJ:.o=.os) - -libthread_db-multi-$(PTHREADS_DEBUG_SUPPORT)+=$(libthread_db_SRC) - -objclean-y+=libthread_db_clean - -lib-a-$(PTHREADS_DEBUG_SUPPORT)+=$(top_builddir)lib/libthread_db.a -lib-so-$(PTHREADS_DEBUG_SUPPORT)+=$(top_builddir)lib/libthread_db.so diff --git a/libpthread/linuxthreads_db/Versions b/libpthread/linuxthreads_db/Versions deleted file mode 100644 index 4ca8042c1..000000000 --- a/libpthread/linuxthreads_db/Versions +++ /dev/null @@ -1,21 +0,0 @@ -libthread_db { - GLIBC_2.1.3 { - # t* - td_init; td_log; td_ta_clear_event; td_ta_delete; td_ta_enable_stats; - td_ta_event_addr; td_ta_event_getmsg; td_ta_get_nthreads; td_ta_get_ph; - td_ta_get_stats; td_ta_map_id2thr; td_ta_map_lwp2thr; td_ta_new; - td_ta_reset_stats; td_ta_set_event; td_ta_setconcurrency; - td_ta_thr_iter; td_ta_tsd_iter; td_thr_clear_event; td_thr_dbresume; - td_thr_dbsuspend; td_thr_event_enable; td_thr_event_getmsg; - td_thr_get_info; td_thr_getfpregs; td_thr_getgregs; td_thr_getxregs; - td_thr_getxregsize; td_thr_set_event; td_thr_setfpregs; td_thr_setgregs; - td_thr_setprio; td_thr_setsigpending; td_thr_setxregs; td_thr_sigsetmask; - td_thr_tsd; td_thr_validate; - } - GLIBC_2.2.3 { - td_symbol_list; - } - GLIBC_2.3 { - td_thr_tls_get_addr; - } -} diff --git a/libpthread/linuxthreads_db/proc_service.h b/libpthread/linuxthreads_db/proc_service.h deleted file mode 100644 index 74136c03e..000000000 --- a/libpthread/linuxthreads_db/proc_service.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (C) 1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -/* The definitions in this file must correspond to those in the debugger. */ -#include - -typedef enum -{ - PS_OK, /* generic "call succeeded" */ - PS_ERR, /* generic. */ - PS_BADPID, /* bad process handle */ - PS_BADLID, /* bad lwp identifier */ - PS_BADADDR, /* bad address */ - PS_NOSYM, /* p_lookup() could not find given symbol */ - PS_NOFREGS - /* - * FPU register set not available for given - * lwp - */ -} ps_err_e; - - -struct ps_prochandle; /* user defined. */ - - -extern ps_err_e ps_pdread(struct ps_prochandle *, - psaddr_t, void *, size_t); -extern ps_err_e ps_pdwrite(struct ps_prochandle *, - psaddr_t, const void *, size_t); -extern ps_err_e ps_ptread(struct ps_prochandle *, - psaddr_t, void *, size_t); -extern ps_err_e ps_ptwrite(struct ps_prochandle *, - psaddr_t, const void *, size_t); - -extern ps_err_e ps_pglobal_lookup(struct ps_prochandle *, - const char *object_name, const char *sym_name, psaddr_t *sym_addr); - - -extern ps_err_e ps_lgetregs(struct ps_prochandle *, - lwpid_t, prgregset_t); -extern ps_err_e ps_lsetregs(struct ps_prochandle *, - lwpid_t, const prgregset_t); -extern ps_err_e ps_lgetfpregs(struct ps_prochandle *, - lwpid_t, prfpregset_t *); -extern ps_err_e ps_lsetfpregs(struct ps_prochandle *, - lwpid_t, const prfpregset_t *); - -extern pid_t ps_getpid (struct ps_prochandle *); - - -extern ps_err_e ps_pstop (const struct ps_prochandle *); -extern ps_err_e ps_pcontinue (const struct ps_prochandle *); - -extern ps_err_e ps_lstop (const struct ps_prochandle *, lwpid_t); -extern ps_err_e ps_lcontinue (const struct ps_prochandle *, lwpid_t); diff --git a/libpthread/linuxthreads_db/td_init.c b/libpthread/linuxthreads_db/td_init.c deleted file mode 100644 index d714f1ba0..000000000 --- a/libpthread/linuxthreads_db/td_init.c +++ /dev/null @@ -1,32 +0,0 @@ -/* Initialization function of thread debugger support library. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - -int __td_debug; - - -td_err_e -td_init (void) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_init"); - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_log.c b/libpthread/linuxthreads_db/td_log.c deleted file mode 100644 index 025273a63..000000000 --- a/libpthread/linuxthreads_db/td_log.c +++ /dev/null @@ -1,32 +0,0 @@ -/* Noop, left for historical reasons. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_log (void) -{ - /* This interface is deprecated in the Sun interface. We provide it - for compatibility but don't do anything ourself. We might in - future do some logging if this seems reasonable. */ - LOG ("td_log"); - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_symbol_list.c b/libpthread/linuxthreads_db/td_symbol_list.c deleted file mode 100644 index 779332b9d..000000000 --- a/libpthread/linuxthreads_db/td_symbol_list.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Return list of symbols the library can request. - Copyright (C) 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 2001. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include "thread_dbP.h" - - -static const char *symbol_list_arr[] = -{ - [PTHREAD_THREADS_EVENTS] = "__pthread_threads_events", - [PTHREAD_LAST_EVENT] = "__pthread_last_event", - [PTHREAD_HANDLES_NUM] = "__pthread_handles_num", - [PTHREAD_HANDLES] = "__pthread_handles", - [PTHREAD_KEYS] = "pthread_keys", - [LINUXTHREADS_PTHREAD_THREADS_MAX] = "__linuxthreads_pthread_threads_max", - [LINUXTHREADS_PTHREAD_KEYS_MAX] = "__linuxthreads_pthread_keys_max", - [LINUXTHREADS_PTHREAD_SIZEOF_DESCR] = "__linuxthreads_pthread_sizeof_descr", - [LINUXTHREADS_CREATE_EVENT] = "__linuxthreads_create_event", - [LINUXTHREADS_DEATH_EVENT] = "__linuxthreads_death_event", - [LINUXTHREADS_REAP_EVENT] = "__linuxthreads_reap_event", - [LINUXTHREADS_INITIAL_REPORT_EVENTS] = "__linuxthreads_initial_report_events", - [LINUXTHREADS_VERSION] = "__linuxthreads_version", - [NUM_MESSAGES] = NULL -}; - - -const char ** -td_symbol_list (void) -{ - return symbol_list_arr; -} - - -int -td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr) -{ - assert (idx >= 0 && idx < NUM_MESSAGES); - return ps_pglobal_lookup (ps, LIBPTHREAD_SO, symbol_list_arr[idx], sym_addr); -} diff --git a/libpthread/linuxthreads_db/td_ta_clear_event.c b/libpthread/linuxthreads_db/td_ta_clear_event.c deleted file mode 100644 index bdbcf47aa..000000000 --- a/libpthread/linuxthreads_db/td_ta_clear_event.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Globally disable events. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_ta_clear_event (ta, event) - const td_thragent_t *ta; - td_thr_events_t *event; -{ - td_thr_events_t old_event; - int i; - - LOG ("td_ta_clear_event"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - /* Write the new value into the thread data structure. */ - if (ps_pdread (ta->ph, ta->pthread_threads_eventsp, - &old_event, sizeof (td_thrhandle_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Remove the set bits in. */ - for (i = 0; i < TD_EVENTSIZE; ++i) - old_event.event_bits[i] &= ~event->event_bits[i]; - - /* Write the new value into the thread data structure. */ - if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp, - &old_event, sizeof (td_thrhandle_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_delete.c b/libpthread/linuxthreads_db/td_ta_delete.c deleted file mode 100644 index 0e6ec17d0..000000000 --- a/libpthread/linuxthreads_db/td_ta_delete.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Detach to target process. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include - -#include "thread_dbP.h" - - -td_err_e -td_ta_delete (td_thragent_t *ta) -{ - LOG ("td_ta_delete"); - - /* Safety check. */ - if (ta == NULL || __td_agent_list == NULL) - return TD_BADTA; - - /* Remove the handle from the list. */ - if (ta == __td_agent_list->ta) - /* It's the first element of the list. */ - __td_agent_list = __td_agent_list->next; - else - { - /* We have to search for it. */ - struct agent_list *runp = __td_agent_list; - - while (runp->next != NULL && runp->next->ta != ta) - runp = runp->next; - - if (runp->next == NULL) - /* It's not a valid decriptor since it is not in the list. */ - return TD_BADTA; - - runp->next = runp->next->next; - } - - /* The handle was allocated in `td_ta_new'. */ - free (ta); - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_enable_stats.c b/libpthread/linuxthreads_db/td_ta_enable_stats.c deleted file mode 100644 index 1d4c34a8d..000000000 --- a/libpthread/linuxthreads_db/td_ta_enable_stats.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Enable collection of statistics for process. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_ta_enable_stats (const td_thragent_t *ta, int enable) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_ta_enable_stats"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_event_addr.c b/libpthread/linuxthreads_db/td_ta_event_addr.c deleted file mode 100644 index 8bce35ae8..000000000 --- a/libpthread/linuxthreads_db/td_ta_event_addr.c +++ /dev/null @@ -1,73 +0,0 @@ -/* Get event address. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_ta_event_addr (const td_thragent_t *ta, td_event_e event, td_notify_t *addr) -{ - td_err_e res = TD_NOEVENT; - int idx = -1; - - LOG ("td_ta_event_addr"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - switch (event) - { - case TD_CREATE: - idx = LINUXTHREADS_CREATE_EVENT; - break; - - case TD_DEATH: - idx = LINUXTHREADS_DEATH_EVENT; - break; - - case TD_REAP: - idx = LINUXTHREADS_REAP_EVENT; - break; - - default: - /* Event cannot be handled. */ - break; - } - - /* Now get the address. */ - if (idx != -1) - { - psaddr_t taddr; - - if (td_lookup (ta->ph, idx, &taddr) == PS_OK) - { - /* Success, we got the address. */ - addr->type = NOTIFY_BPT; - addr->u.bptaddr = taddr; - - res = TD_OK; - } - else - res = TD_ERR; - } - - return res; -} diff --git a/libpthread/linuxthreads_db/td_ta_event_getmsg.c b/libpthread/linuxthreads_db/td_ta_event_getmsg.c deleted file mode 100644 index ec68ae0e2..000000000 --- a/libpthread/linuxthreads_db/td_ta_event_getmsg.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Retrieve event. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include - -#include "thread_dbP.h" -#include "../linuxthreads/internals.h" - - -td_err_e -td_ta_event_getmsg (const td_thragent_t *ta, td_event_msg_t *msg) -{ - /* XXX I cannot think of another way but using a static variable. */ - static td_thrhandle_t th; - td_eventbuf_t event; - psaddr_t addr; - - LOG ("td_ta_event_getmsg"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - /* Get the pointer to the thread descriptor with the last event. */ - if (ps_pdread (ta->ph, ta->pthread_last_event, - &addr, sizeof (void *)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* If the pointer is NULL no event occurred. */ - if (addr == 0) - return TD_NOMSG; - - /* Read the even structure from the target. */ - if (ps_pdread (ta->ph, - ((char *) addr - + offsetof (struct _pthread_descr_struct, p_eventbuf)), - &event, sizeof (td_eventbuf_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Check whether an event occurred. */ - if (event.eventnum == TD_EVENT_NONE) - { - /* Oh well, this means the last event was already read. So - we have to look for any other event. */ - struct pthread_handle_struct handles[ta->pthread_threads_max]; - int num; - int i; - - /* Read the number of currently active threads. */ - if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) - != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Now read the handles. */ - if (ps_pdread (ta->ph, ta->handles, handles, - ta->pthread_threads_max * sizeof (handles[0])) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - for (i = 0; i < ta->pthread_threads_max && num > 0; ++i) - { - if (handles[i].h_descr == NULL) - /* No entry here. */ - continue; - - /* First count this active thread. */ - --num; - - if (handles[i].h_descr == addr) - /* We already handled this. */ - continue; - - /* Read the event data for this thread. */ - if (ps_pdread (ta->ph, - ((char *) handles[i].h_descr - + offsetof (struct _pthread_descr_struct, - p_eventbuf)), - &event, sizeof (td_eventbuf_t)) != PS_OK) - return TD_ERR; - - if (event.eventnum != TD_EVENT_NONE) - { - /* We found a thread with an unreported event. */ - addr = handles[i].h_descr; - break; - } - } - - /* If we haven't found any other event signal this to the user. */ - if (event.eventnum == TD_EVENT_NONE) - return TD_NOMSG; - } - - /* Generate the thread descriptor. */ - th.th_ta_p = (td_thragent_t *) ta; - th.th_unique = addr; - - /* Fill the user's data structure. */ - msg->event = event.eventnum; - msg->th_p = &th; - msg->msg.data = (uintptr_t) event.eventdata; - - /* And clear the event message in the target. */ - memset (&event, '\0', sizeof (td_eventbuf_t)); - if (ps_pdwrite (ta->ph, - ((char *) addr - + offsetof (struct _pthread_descr_struct, p_eventbuf)), - &event, sizeof (td_eventbuf_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_get_nthreads.c b/libpthread/linuxthreads_db/td_ta_get_nthreads.c deleted file mode 100644 index 839b56be5..000000000 --- a/libpthread/linuxthreads_db/td_ta_get_nthreads.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Get the number of threads in the process. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - -td_err_e -td_ta_get_nthreads (const td_thragent_t *ta, int *np) -{ - psaddr_t addr; - - LOG ("td_ta_get_nthreads"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - /* Access the variable `__pthread_handles_num'. */ - if (td_lookup (ta->ph, PTHREAD_HANDLES_NUM, &addr) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - if (ps_pdread (ta->ph, addr, np, sizeof (int)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_get_ph.c b/libpthread/linuxthreads_db/td_ta_get_ph.c deleted file mode 100644 index 23d328508..000000000 --- a/libpthread/linuxthreads_db/td_ta_get_ph.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Get external process handle. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_ta_get_ph (const td_thragent_t *ta, struct ps_prochandle **ph) -{ - LOG ("td_ta_get_ph"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - *ph = ta->ph; - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_get_stats.c b/libpthread/linuxthreads_db/td_ta_get_stats.c deleted file mode 100644 index 6bf2f5352..000000000 --- a/libpthread/linuxthreads_db/td_ta_get_stats.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Retrieve statistics for process. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_ta_get_stats (const td_thragent_t *ta, td_ta_stats_t *statsp) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_ta_get_stats"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_map_id2thr.c b/libpthread/linuxthreads_db/td_ta_map_id2thr.c deleted file mode 100644 index ddb6492e2..000000000 --- a/libpthread/linuxthreads_db/td_ta_map_id2thr.c +++ /dev/null @@ -1,79 +0,0 @@ -/* Map thread ID to thread handle. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" -#include "../linuxthreads/internals.h" - - -td_err_e -td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th) -{ - struct pthread_handle_struct phc; - struct _pthread_descr_struct pds; - int pthread_threads_max; - - LOG ("td_ta_map_id2thr"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - /* Make the following expression a bit smaller. */ - pthread_threads_max = ta->pthread_threads_max; - - /* We can compute the entry in the handle array we want. */ - if (ps_pdread (ta->ph, ta->handles + pt % pthread_threads_max, &phc, - sizeof (struct pthread_handle_struct)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Test whether this entry is in use. */ - if (phc.h_descr == NULL) - { - if (pt % pthread_threads_max == 0) - { - /* The initial thread always exists but the thread library - might not yet be initialized. */ - th->th_ta_p = (td_thragent_t *) ta; - th->th_unique = NULL; - - return TD_OK; - } - - return TD_BADTH; - } - - /* Next test: get the descriptor to see whether this is not an old - thread handle. */ - if (ps_pdread (ta->ph, phc.h_descr, &pds, - sizeof (struct _pthread_descr_struct)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - if (pds.p_tid != pt) - return TD_BADTH; - - if (pds.p_terminated != 0) - return TD_NOTHR; - - /* Create the `td_thrhandle_t' object. */ - th->th_ta_p = (td_thragent_t *) ta; - th->th_unique = phc.h_descr; - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_map_lwp2thr.c b/libpthread/linuxthreads_db/td_ta_map_lwp2thr.c deleted file mode 100644 index 1337a5c68..000000000 --- a/libpthread/linuxthreads_db/td_ta_map_lwp2thr.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Which thread is running on an lwp? - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" -#include "../linuxthreads/internals.h" - - -td_err_e -td_ta_map_lwp2thr (const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th) -{ - int pthread_threads_max = ta->pthread_threads_max; - size_t sizeof_descr = ta->sizeof_descr; - struct pthread_handle_struct phc[pthread_threads_max]; - size_t cnt; -#ifdef ALL_THREADS_STOPPED - int num; -#else -# define num 1 -#endif - - LOG ("td_ta_map_lwp2thr"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - /* Read all the descriptors. */ - if (ps_pdread (ta->ph, ta->handles, phc, - sizeof (struct pthread_handle_struct) * pthread_threads_max) - != PS_OK) - return TD_ERR; /* XXX Other error value? */ - -#ifdef ALL_THREADS_STOPPED - /* Read the number of currently active threads. */ - if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ -#endif - - /* Get the entries one after the other and find out whether the ID - matches. */ - for (cnt = 0; cnt < pthread_threads_max && num > 0; ++cnt) - if (phc[cnt].h_descr != NULL) - { - struct _pthread_descr_struct pds; - -#ifdef ALL_THREADS_STOPPED - /* First count this active thread. */ - --num; -#endif - - if (ps_pdread (ta->ph, phc[cnt].h_descr, &pds, sizeof_descr) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - if ((pds.p_pid ?: ps_getpid (ta->ph)) == lwpid) - { - /* Found it. Now fill in the `td_thrhandle_t' object. */ - th->th_ta_p = (td_thragent_t *) ta; - th->th_unique = phc[cnt].h_descr; - - return TD_OK; - } - } - else if (cnt == 0) - { - /* The initial thread always exists. But it might not yet be - initialized. Construct a value. */ - th->th_ta_p = (td_thragent_t *) ta; - th->th_unique = NULL; - - return TD_OK; - } - - return TD_NOLWP; -} diff --git a/libpthread/linuxthreads_db/td_ta_new.c b/libpthread/linuxthreads_db/td_ta_new.c deleted file mode 100644 index 9bf926719..000000000 --- a/libpthread/linuxthreads_db/td_ta_new.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Attach to target process. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include -#include - -#include "thread_dbP.h" - - -/* Datatype for the list of known thread agents. Normally there will - be exactly one so we don't spend much though on making it fast. */ -struct agent_list *__td_agent_list; - - -td_err_e -td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta) -{ - psaddr_t addr; - psaddr_t versaddr; - char versbuf[sizeof (VERSION)]; - struct agent_list *elemp; - - LOG ("td_ta_new"); - - /* Get the global event mask. This is one of the variables which - are new in the thread library to enable debugging. If it is - not available we cannot debug. */ - if (td_lookup (ps, PTHREAD_THREADS_EVENTS, &addr) != PS_OK) - return TD_NOLIBTHREAD; - - /* Check whether the versions match. */ - if (td_lookup (ps, LINUXTHREADS_VERSION, &versaddr) != PS_OK) - return TD_VERSION; - if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK) - return TD_ERR; - - versbuf[sizeof (versbuf) - 1] = '\0'; - if (strcmp (versbuf, VERSION) != 0) - /* Not the right version. */ - return TD_VERSION; - - /* Fill in the appropriate information. */ - *ta = (td_thragent_t *) malloc (sizeof (td_thragent_t)); - if (*ta == NULL) - return TD_MALLOC; - - /* Store the proc handle which we will pass to the callback functions - back into the debugger. */ - (*ta)->ph = ps; - - /* Remember the address. */ - (*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr; - - /* Get the pointer to the variable pointing to the thread descriptor - with the last event. */ - if (td_lookup (ps, PTHREAD_LAST_EVENT, &(*ta)->pthread_last_event) != PS_OK) - { - free_return: - free (*ta); - return TD_ERR; - } - - /* Get the pointer to the variable containing the number of active - threads. */ - if (td_lookup (ps, PTHREAD_HANDLES_NUM, &(*ta)->pthread_handles_num) - != PS_OK) - goto free_return; - - /* See whether the library contains the necessary symbols. */ - if (td_lookup (ps, PTHREAD_HANDLES, &addr) != PS_OK) - goto free_return; - - (*ta)->handles = (struct pthread_handle_struct *) addr; - - - if (td_lookup (ps, PTHREAD_KEYS, &addr) != PS_OK) - goto free_return; - - /* Cast to the right type. */ - (*ta)->keys = (struct pthread_key_struct *) addr; - - /* Find out about the maximum number of threads. Old implementations - don't provide this information. In this case we assume that the - debug library is compiled with the same values. */ - if (td_lookup (ps, LINUXTHREADS_PTHREAD_THREADS_MAX, &addr) != PS_OK) - (*ta)->pthread_threads_max = PTHREAD_THREADS_MAX; - else - { - if (ps_pdread (ps, addr, &(*ta)->pthread_threads_max, sizeof (int)) - != PS_OK) - goto free_return; - } - - /* Similar for the maximum number of thread local data keys. */ - if (td_lookup (ps, LINUXTHREADS_PTHREAD_KEYS_MAX, &addr) != PS_OK) - (*ta)->pthread_keys_max = PTHREAD_KEYS_MAX; - else - { - if (ps_pdread (ps, addr, &(*ta)->pthread_keys_max, sizeof (int)) - != PS_OK) - goto free_return; - } - - /* And for the size of the second level arrays for the keys. */ - if (td_lookup (ps, LINUXTHREADS_PTHREAD_SIZEOF_DESCR, &addr) != PS_OK) - (*ta)->sizeof_descr = sizeof (struct _pthread_descr_struct); - else - { - if (ps_pdread (ps, addr, &(*ta)->sizeof_descr, sizeof (int)) != PS_OK) - goto free_return; - /* Don't let bogons in the inferior make us mess ourselves. */ - if ((*ta)->sizeof_descr > sizeof (struct _pthread_descr_struct)) - (*ta)->sizeof_descr = sizeof (struct _pthread_descr_struct); - - } - - /* Now add the new agent descriptor to the list. */ - elemp = (struct agent_list *) malloc (sizeof (struct agent_list)); - if (elemp == NULL) - { - /* Argh, now that everything else worked... */ - free (*ta); - return TD_MALLOC; - } - - /* We don't care for thread-safety here. */ - elemp->ta = *ta; - elemp->next = __td_agent_list; - __td_agent_list = elemp; - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_reset_stats.c b/libpthread/linuxthreads_db/td_ta_reset_stats.c deleted file mode 100644 index b3ddbd07b..000000000 --- a/libpthread/linuxthreads_db/td_ta_reset_stats.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Reset statistics. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_ta_reset_stats (const td_thragent_t *ta) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_ta_reset_stats"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_set_event.c b/libpthread/linuxthreads_db/td_ta_set_event.c deleted file mode 100644 index 73cf9f405..000000000 --- a/libpthread/linuxthreads_db/td_ta_set_event.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Globally enable events. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_ta_set_event (ta, event) - const td_thragent_t *ta; - td_thr_events_t *event; -{ - td_thr_events_t old_event; - int i; - - LOG ("td_ta_set_event"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - /* Write the new value into the thread data structure. */ - if (ps_pdread (ta->ph, ta->pthread_threads_eventsp, - &old_event, sizeof (td_thrhandle_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Or the new bits in. */ - for (i = 0; i < TD_EVENTSIZE; ++i) - old_event.event_bits[i] |= event->event_bits[i]; - - /* Write the new value into the thread data structure. */ - if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp, - &old_event, sizeof (td_thrhandle_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_ta_setconcurrency.c b/libpthread/linuxthreads_db/td_ta_setconcurrency.c deleted file mode 100644 index 408e76309..000000000 --- a/libpthread/linuxthreads_db/td_ta_setconcurrency.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Set suggested concurrency level for process. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_ta_setconcurrency (const td_thragent_t *ta, int level) -{ - /* This is something LinuxThreads does not support. */ - LOG ("td_ta_setconcurrency"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - return TD_NOCAPAB; -} diff --git a/libpthread/linuxthreads_db/td_ta_thr_iter.c b/libpthread/linuxthreads_db/td_ta_thr_iter.c deleted file mode 100644 index 2dad149d5..000000000 --- a/libpthread/linuxthreads_db/td_ta_thr_iter.c +++ /dev/null @@ -1,174 +0,0 @@ -/* Iterate over a process's threads. - Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" -#include "../linuxthreads/internals.h" -#include - -static int -handle_descr (const td_thragent_t *ta, td_thr_iter_f *callback, - void *cbdata_p, td_thr_state_e state, int ti_pri, - size_t cnt, pthread_descr descr) -{ - struct _pthread_descr_struct pds; - size_t sizeof_descr = ta->sizeof_descr; - td_thrhandle_t th; - - if (descr == NULL) - { - /* No descriptor (yet). */ - if (cnt == 0) - { - /* This is the main thread. Create a fake descriptor. */ - memset (&pds, '\0', sizeof (pds)); - - /* Empty thread descriptor the thread library would create. */ - pds.p_self = &pds; - pds.p_nextlive = pds.p_prevlive = &pds; - pds.p_tid = PTHREAD_THREADS_MAX; - /* The init code also sets up p_lock, p_errnop, p_herrnop, and - p_userstack but this should not be necessary here. */ - - th.th_ta_p = (td_thragent_t *) ta; - th.th_unique = NULL; - if (callback (&th, cbdata_p) != 0) - return TD_DBERR; - - /* All done successfully. */ - return TD_OK; - } - else if (cnt == 1) - /* The manager is not yet started. No big deal. */ - return TD_OK; - else - /* For every other thread this should not happen. */ - return TD_ERR; - } - - if (ps_pdread (ta->ph, descr, &pds, sizeof_descr) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* The manager thread must be handled special. The descriptor - exists but the thread only gets created when the first - `pthread_create' call is issued. A clear indication that this - happened is when the p_pid field is non-zero. */ - if (cnt == 1 && pds.p_pid == 0) - return TD_OK; - - /* Now test whether this thread matches the specified - conditions. */ - - /* Only if the priority level is as high or higher. */ - if (pds.p_priority < ti_pri) - return TD_OK; - - /* Test the state. - XXX This is incomplete. */ - if (state != TD_THR_ANY_STATE) - return TD_OK; - - /* XXX For now we ignore threads which are not running anymore. - The reason is that gdb tries to get the registers and fails. - In future we should have a special mode of the thread library - in which we keep the process around until the actual join - operation happened. */ - if (pds.p_exited != 0) - return TD_OK; - - /* Yep, it matches. Call the callback function. */ - th.th_ta_p = (td_thragent_t *) ta; - th.th_unique = descr; - if (callback (&th, cbdata_p) != 0) - return TD_DBERR; - - /* All done successfully. */ - return TD_OK; -} - - -td_err_e -td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback, - void *cbdata_p, td_thr_state_e state, int ti_pri, - sigset_t *ti_sigmask_p, unsigned int ti_user_flags) -{ - int pthread_threads_max; - struct pthread_handle_struct *phc; - td_err_e result = TD_OK; - int cnt; -#ifdef ALL_THREADS_STOPPED - int num; -#else -# define num 1 -#endif - - LOG ("td_ta_thr_iter"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - pthread_threads_max = ta->pthread_threads_max; - phc = (struct pthread_handle_struct *) alloca (sizeof (phc[0]) - * pthread_threads_max); - - /* First read only the main thread and manager thread information. */ - if (ps_pdread (ta->ph, ta->handles, phc, - sizeof (struct pthread_handle_struct) * 2) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Now handle these descriptors. */ - result = handle_descr (ta, callback, cbdata_p, state, ti_pri, 0, - phc[0].h_descr); - if (result != TD_OK) - return result; - result = handle_descr (ta, callback, cbdata_p, state, ti_pri, 1, - phc[1].h_descr); - if (result != TD_OK) - return result; - - /* Read all the descriptors. */ - if (ps_pdread (ta->ph, ta->handles + 2, &phc[2], - (sizeof (struct pthread_handle_struct) - * (pthread_threads_max - 2))) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - -#ifdef ALL_THREADS_STOPPED - /* Read the number of currently active threads. */ - if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ -#endif - - /* Now get all descriptors, one after the other. */ - for (cnt = 2; cnt < pthread_threads_max && num > 0; ++cnt) - if (phc[cnt].h_descr != NULL) - { -#ifdef ALL_THREADS_STOPPED - /* First count this active thread. */ - --num; -#endif - - result = handle_descr (ta, callback, cbdata_p, state, ti_pri, cnt, - phc[cnt].h_descr); - if (result != TD_OK) - break; - } - - return result; -} diff --git a/libpthread/linuxthreads_db/td_ta_tsd_iter.c b/libpthread/linuxthreads_db/td_ta_tsd_iter.c deleted file mode 100644 index 9e24250c6..000000000 --- a/libpthread/linuxthreads_db/td_ta_tsd_iter.c +++ /dev/null @@ -1,56 +0,0 @@ -/* Iterate over a process's thread-specific data. - Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" -#include "../linuxthreads/internals.h" -#include - -td_err_e -td_ta_tsd_iter (const td_thragent_t *ta, td_key_iter_f *callback, - void *cbdata_p) -{ - struct pthread_key_struct *keys; - int pthread_keys_max; - int cnt; - - LOG ("td_ta_tsd_iter"); - - /* Test whether the TA parameter is ok. */ - if (! ta_ok (ta)) - return TD_BADTA; - - pthread_keys_max = ta->pthread_keys_max; - keys = (struct pthread_key_struct *) alloca (sizeof (keys[0]) - * pthread_keys_max); - - /* Read all the information about the keys. */ - if (ps_pdread (ta->ph, ta->keys, keys, - sizeof (keys[0]) * pthread_keys_max) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Now get all descriptors, one after the other. */ - for (cnt = 0; cnt < pthread_keys_max; ++cnt) - if (keys[cnt].in_use - /* Return with an error if the callback returns a nonzero value. */ - && callback (cnt, keys[cnt].destr, cbdata_p) != 0) - return TD_DBERR; - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_clear_event.c b/libpthread/linuxthreads_db/td_thr_clear_event.c deleted file mode 100644 index c027fc09f..000000000 --- a/libpthread/linuxthreads_db/td_thr_clear_event.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Disable specific event for thread. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include - -#include "thread_dbP.h" - - -td_err_e -td_thr_clear_event (th, event) - const td_thrhandle_t *th; - td_thr_events_t *event; -{ - td_thr_events_t old_event; - int i; - - LOG ("td_thr_clear_event"); - - /* If the thread descriptor has not yet been constructed do not do - anything. */ - if (th->th_unique == NULL) - return TD_OK; - - /* Write the new value into the thread data structure. */ - if (ps_pdread (th->th_ta_p->ph, - ((char *) th->th_unique - + offsetof (struct _pthread_descr_struct, - p_eventbuf.eventmask)), - &old_event, sizeof (td_thrhandle_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Remove the set bits in. */ - for (i = 0; i < TD_EVENTSIZE; ++i) - old_event.event_bits[i] &= ~event->event_bits[i]; - - /* Write the new value into the thread data structure. */ - if (ps_pdwrite (th->th_ta_p->ph, - ((char *) th->th_unique - + offsetof (struct _pthread_descr_struct, - p_eventbuf.eventmask)), - &old_event, sizeof (td_thrhandle_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_dbresume.c b/libpthread/linuxthreads_db/td_thr_dbresume.c deleted file mode 100644 index 7b7f6eef9..000000000 --- a/libpthread/linuxthreads_db/td_thr_dbresume.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Resume execution of given thread. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_dbresume (const td_thrhandle_t *th) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_thr_dbresume"); - return TD_NOCAPAB; -} diff --git a/libpthread/linuxthreads_db/td_thr_dbsuspend.c b/libpthread/linuxthreads_db/td_thr_dbsuspend.c deleted file mode 100644 index ef668023d..000000000 --- a/libpthread/linuxthreads_db/td_thr_dbsuspend.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Suspend execution of given thread. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_dbsuspend (const td_thrhandle_t *th) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_thr_dbsuspend"); - return TD_NOCAPAB; -} diff --git a/libpthread/linuxthreads_db/td_thr_event_enable.c b/libpthread/linuxthreads_db/td_thr_event_enable.c deleted file mode 100644 index 407f3fc44..000000000 --- a/libpthread/linuxthreads_db/td_thr_event_enable.c +++ /dev/null @@ -1,57 +0,0 @@ -/* Enable event process-wide. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include - -#include "thread_dbP.h" - - -td_err_e -td_thr_event_enable (th, onoff) - const td_thrhandle_t *th; - int onoff; -{ - LOG ("td_thr_event_enable"); - - /* Write the new value into the thread data structure. */ - if (th->th_unique == NULL) - { - psaddr_t addr; - - if (td_lookup (th->th_ta_p->ph, LINUXTHREADS_INITIAL_REPORT_EVENTS, - &addr) != PS_OK) - /* Cannot read the symbol. This should not happen. */ - return TD_ERR; - - if (ps_pdwrite (th->th_ta_p->ph, addr, &onoff, sizeof (int)) != PS_OK) - return TD_ERR; - - return TD_OK; - } - - if (ps_pdwrite (th->th_ta_p->ph, - ((char *) th->th_unique - + offsetof (struct _pthread_descr_struct, - p_report_events)), - &onoff, sizeof (int)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_event_getmsg.c b/libpthread/linuxthreads_db/td_thr_event_getmsg.c deleted file mode 100644 index bf4ddd4ad..000000000 --- a/libpthread/linuxthreads_db/td_thr_event_getmsg.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Retrieve event. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include - -#include "thread_dbP.h" - - -td_err_e -td_thr_event_getmsg (const td_thrhandle_t *th, td_event_msg_t *msg) -{ - td_eventbuf_t event; - - LOG ("td_thr_event_getmsg"); - - /* If the thread descriptor has not yet been created there cannot be - any event. */ - if (th->th_unique == NULL) - return TD_NOMSG; - - /* Read the even structure from the target. */ - if (ps_pdread (th->th_ta_p->ph, - ((char *) th->th_unique - + offsetof (struct _pthread_descr_struct, p_eventbuf)), - &event, sizeof (td_eventbuf_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Check whether an event occurred. */ - if (event.eventnum == TD_EVENT_NONE) - /* Nothing. */ - return TD_NOMSG; - - /* Fill the user's data structure. */ - msg->event = event.eventnum; - msg->th_p = th; - msg->msg.data = (uintptr_t) event.eventdata; - - /* And clear the event message in the target. */ - memset (&event, '\0', sizeof (td_eventbuf_t)); - if (ps_pdwrite (th->th_ta_p->ph, - ((char *) th->th_unique - + offsetof (struct _pthread_descr_struct, p_eventbuf)), - &event, sizeof (td_eventbuf_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_get_info.c b/libpthread/linuxthreads_db/td_thr_get_info.c deleted file mode 100644 index 4666bda97..000000000 --- a/libpthread/linuxthreads_db/td_thr_get_info.c +++ /dev/null @@ -1,83 +0,0 @@ -/* Get thread information. - Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include -#include - -#include "thread_dbP.h" - - -td_err_e -td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop) -{ - struct _pthread_descr_struct pds; - - LOG ("td_thr_get_info"); - - /* Handle the case when the thread library is not yet initialized. */ - if (th->th_unique == NULL) - { - memset (&pds, '\0', sizeof (pds)); - pds.p_tid = PTHREAD_THREADS_MAX; - } - else - /* Get the thread descriptor. */ - if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, - th->th_ta_p->sizeof_descr) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Fill in information. Clear first to provide reproducable - results for the fields we do not fill in. */ - memset (infop, '\0', sizeof (td_thrinfo_t)); - - /* We have to handle the manager thread special since the thread - descriptor in older versions is not fully initialized. */ - if (pds.p_nr == 1) - { - infop->ti_tid = th->th_ta_p->pthread_threads_max * 2 + 1; - infop->ti_type = TD_THR_SYSTEM; - infop->ti_state = TD_THR_ACTIVE; - } - else - { - infop->ti_tid = pds.p_tid; - infop->ti_tls = (char *) pds.p_specific; - infop->ti_pri = pds.p_priority; - infop->ti_type = TD_THR_USER; - - if (! pds.p_terminated) - /* XXX For now there is no way to get more information. */ - infop->ti_state = TD_THR_ACTIVE; - else if (! pds.p_detached) - infop->ti_state = TD_THR_ZOMBIE; - else - infop->ti_state = TD_THR_UNKNOWN; - } - - /* Initialization which are the same in both cases. */ - infop->ti_lid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); - infop->ti_ta_p = th->th_ta_p; - infop->ti_startfunc = pds.p_start_args.start_routine; - memcpy (&infop->ti_events, &pds.p_eventbuf.eventmask, - sizeof (td_thr_events_t)); - infop->ti_traceme = pds.p_report_events != 0; - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_getfpregs.c b/libpthread/linuxthreads_db/td_thr_getfpregs.c deleted file mode 100644 index 31c55c876..000000000 --- a/libpthread/linuxthreads_db/td_thr_getfpregs.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Get a thread's floating-point register set. - Copyright (C) 1999, 2001, 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_getfpregs (const td_thrhandle_t *th, prfpregset_t *regset) -{ - struct _pthread_descr_struct pds; - - LOG ("td_thr_getfpregs"); - - if (th->th_unique == NULL) - { - /* No data yet. Use the main thread. */ - pid_t pid = ps_getpid (th->th_ta_p->ph); - if (ps_lgetfpregs (th->th_ta_p->ph, pid, regset) != PS_OK) - return TD_ERR; - return TD_OK; - } - - /* We have to get the state and the PID for this thread. */ - if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, - sizeof (struct _pthread_descr_struct)) != PS_OK) - return TD_ERR; - - /* If the thread already terminated we return all zeroes. */ - if (pds.p_terminated) - memset (regset, '\0', sizeof (*regset)); - /* Otherwise get the register content through the callback. */ - else - { - pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); - - if (ps_lgetfpregs (th->th_ta_p->ph, pid, regset) != PS_OK) - return TD_ERR; - } - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_getgregs.c b/libpthread/linuxthreads_db/td_thr_getgregs.c deleted file mode 100644 index a9ec6a37d..000000000 --- a/libpthread/linuxthreads_db/td_thr_getgregs.c +++ /dev/null @@ -1,58 +0,0 @@ -/* Get a thread's general register set. - Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_getgregs (const td_thrhandle_t *th, prgregset_t gregs) -{ - struct _pthread_descr_struct pds; - - LOG ("td_thr_getgregs"); - - if (th->th_unique == NULL) - { - /* No data yet. Use the main thread. */ - pid_t pid = ps_getpid (th->th_ta_p->ph); - if (ps_lgetregs (th->th_ta_p->ph, pid, gregs) != PS_OK) - return TD_ERR; - return TD_OK; - } - - /* We have to get the state and the PID for this thread. */ - if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, - sizeof (struct _pthread_descr_struct)) != PS_OK) - return TD_ERR; - - /* If the thread already terminated we return all zeroes. */ - if (pds.p_terminated) - memset (gregs, '\0', sizeof (prgregset_t)); - /* Otherwise get the register content through the callback. */ - else - { - pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); - - if (ps_lgetregs (th->th_ta_p->ph, pid, gregs) != PS_OK) - return TD_ERR; - } - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_getxregs.c b/libpthread/linuxthreads_db/td_thr_getxregs.c deleted file mode 100644 index 39cd73cf1..000000000 --- a/libpthread/linuxthreads_db/td_thr_getxregs.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Get a thread's extra state register set. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_getxregs (const td_thrhandle_t *th, void *xregs) -{ - /* XXX This might be platform specific. */ - LOG ("td_thr_getxregs"); - return TD_NOXREGS; -} diff --git a/libpthread/linuxthreads_db/td_thr_getxregsize.c b/libpthread/linuxthreads_db/td_thr_getxregsize.c deleted file mode 100644 index 5d8ac288e..000000000 --- a/libpthread/linuxthreads_db/td_thr_getxregsize.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Get the size of the extra state register set for this architecture. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_getxregsize (const td_thrhandle_t *th, int *sizep) -{ - /* XXX This might be platform specific. */ - LOG ("td_thr_getxregsize"); - return TD_NOXREGS; -} diff --git a/libpthread/linuxthreads_db/td_thr_set_event.c b/libpthread/linuxthreads_db/td_thr_set_event.c deleted file mode 100644 index 205b445c7..000000000 --- a/libpthread/linuxthreads_db/td_thr_set_event.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Enable specific event for thread. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include - -#include "thread_dbP.h" - - -td_err_e -td_thr_set_event (th, event) - const td_thrhandle_t *th; - td_thr_events_t *event; -{ - td_thr_events_t old_event; - int i; - - LOG ("td_thr_set_event"); - - /* What shall we do if no thread descriptor exists but the user - wants to set an event? */ - if (th->th_unique == NULL) - return TD_NOTALLOC; - - /* Write the new value into the thread data structure. */ - if (ps_pdread (th->th_ta_p->ph, - ((char *) th->th_unique - + offsetof (struct _pthread_descr_struct, - p_eventbuf.eventmask)), - &old_event, sizeof (td_thrhandle_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Or the new bits in. */ - for (i = 0; i < TD_EVENTSIZE; ++i) - old_event.event_bits[i] |= event->event_bits[i]; - - /* Write the new value into the thread data structure. */ - if (ps_pdwrite (th->th_ta_p->ph, - ((char *) th->th_unique - + offsetof (struct _pthread_descr_struct, - p_eventbuf.eventmask)), - &old_event, sizeof (td_thrhandle_t)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_setfpregs.c b/libpthread/linuxthreads_db/td_thr_setfpregs.c deleted file mode 100644 index e4d9ec65e..000000000 --- a/libpthread/linuxthreads_db/td_thr_setfpregs.c +++ /dev/null @@ -1,47 +0,0 @@ -/* Set a thread's floating-point register set. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_setfpregs (const td_thrhandle_t *th, const prfpregset_t *fpregs) -{ - struct _pthread_descr_struct pds = { .p_terminated = 0, .p_pid = 0 }; - - LOG ("td_thr_setfpregs"); - - /* We have to get the state and the PID for this thread. */ - if (th->th_unique != NULL - && ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, - sizeof (struct _pthread_descr_struct)) != PS_OK) - return TD_ERR; - - /* Only set the registers if the thread hasn't yet terminated. */ - if (pds.p_terminated == 0) - { - pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); - - if (ps_lsetfpregs (th->th_ta_p->ph, pid, fpregs) != PS_OK) - return TD_ERR; - } - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_setgregs.c b/libpthread/linuxthreads_db/td_thr_setgregs.c deleted file mode 100644 index 8c021a473..000000000 --- a/libpthread/linuxthreads_db/td_thr_setgregs.c +++ /dev/null @@ -1,47 +0,0 @@ -/* Set a thread's general register set. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs) -{ - struct _pthread_descr_struct pds = { .p_terminated = 0, .p_pid = 0 }; - - LOG ("td_thr_setgregs"); - - /* We have to get the state and the PID for this thread. */ - if (th->th_unique != NULL - && ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, - sizeof (struct _pthread_descr_struct)) != PS_OK) - return TD_ERR; - - /* Only set the registers if the thread hasn't yet terminated. */ - if (pds.p_terminated == 0) - { - pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph); - - if (ps_lsetregs (th->th_ta_p->ph, pid, gregs) != PS_OK) - return TD_ERR; - } - - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_setprio.c b/libpthread/linuxthreads_db/td_thr_setprio.c deleted file mode 100644 index 98d202dfe..000000000 --- a/libpthread/linuxthreads_db/td_thr_setprio.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Set a thread's priority. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_setprio (const td_thrhandle_t *th, int prio) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_thr_setprio"); - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_setsigpending.c b/libpthread/linuxthreads_db/td_thr_setsigpending.c deleted file mode 100644 index 98e30140e..000000000 --- a/libpthread/linuxthreads_db/td_thr_setsigpending.c +++ /dev/null @@ -1,31 +0,0 @@ -/* Raise a signal for a thread. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_setsigpending (const td_thrhandle_t *th, unsigned char n, - const sigset_t *ss) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_thr_setsigpending"); - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_setxregs.c b/libpthread/linuxthreads_db/td_thr_setxregs.c deleted file mode 100644 index da77ab3b4..000000000 --- a/libpthread/linuxthreads_db/td_thr_setxregs.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Set a thread's extra state register set. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_setxregs (const td_thrhandle_t *ta, const void *addr) -{ - /* XXX This might have to be platform specific. */ - LOG ("td_thr_setxregs"); - return TD_NOXREGS; -} diff --git a/libpthread/linuxthreads_db/td_thr_sigsetmask.c b/libpthread/linuxthreads_db/td_thr_sigsetmask.c deleted file mode 100644 index 8b0eb8185..000000000 --- a/libpthread/linuxthreads_db/td_thr_sigsetmask.c +++ /dev/null @@ -1,30 +0,0 @@ -/* Set a thread's signal mask. - Copyright (C) 1999, 2001 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" - - -td_err_e -td_thr_sigsetmask (const td_thrhandle_t *th, const sigset_t *ss) -{ - /* XXX We have to figure out what has to be done. */ - LOG ("td_thr_sigsetmask"); - return TD_OK; -} diff --git a/libpthread/linuxthreads_db/td_thr_tls_get_addr.c b/libpthread/linuxthreads_db/td_thr_tls_get_addr.c deleted file mode 100644 index e140b77dc..000000000 --- a/libpthread/linuxthreads_db/td_thr_tls_get_addr.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Get address of thread local variable. - Copyright (C) 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 2002. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - - -#include "link.h" -#include "thread_dbP.h" - -/* Value used for dtv entries for which the allocation is delayed. */ -# define TLS_DTV_UNALLOCATED ((void *) -1l) - - -td_err_e -td_thr_tls_get_addr (const td_thrhandle_t *th __attribute__ ((unused)), - void *map_address __attribute__ ((unused)), - size_t offset __attribute__ ((unused)), - void **address __attribute__ ((unused))) -{ -#if USE_TLS - size_t modid; - union dtv pdtv, *dtvp; - - LOG ("td_thr_tls_get_addr"); - - /* Get the DTV pointer from the thread descriptor. */ - if (ps_pdread (th->th_ta_p->ph, - &((struct _pthread_descr_struct *) th->th_unique)->p_header.data.dtvp, - &dtvp, sizeof dtvp) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Read the module ID from the link_map. */ - if (ps_pdread (th->th_ta_p->ph, - &((struct link_map *) map_address)->l_tls_modid, - &modid, sizeof modid) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Get the corresponding entry in the DTV. */ - if (ps_pdread (th->th_ta_p->ph, dtvp + modid, - &pdtv, sizeof (union dtv)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* It could be that the memory for this module is not allocated for - the given thread. */ - if (pdtv.pointer == TLS_DTV_UNALLOCATED) - /* There is not much we can do. */ - return TD_NOTALLOC; - - *address = (char *) pdtv.pointer + offset; - - return TD_OK; -#else - return TD_ERR; -#endif -} diff --git a/libpthread/linuxthreads_db/td_thr_tsd.c b/libpthread/linuxthreads_db/td_thr_tsd.c deleted file mode 100644 index f2cdefcfa..000000000 --- a/libpthread/linuxthreads_db/td_thr_tsd.c +++ /dev/null @@ -1,82 +0,0 @@ -/* Get a thread-specific data pointer for a thread. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" -#include "../linuxthreads/internals.h" - - -td_err_e -td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data) -{ - struct _pthread_descr_struct pds; - struct pthread_key_struct *keys = th->th_ta_p->keys; - struct pthread_key_struct key; - int pthread_keys_max = th->th_ta_p->pthread_keys_max; - int pthread_key_2ndlevel_size = th->th_ta_p->pthread_key_2ndlevel_size; - unsigned int idx1st; - unsigned int idx2nd; - void *p; - - LOG ("td_thr_tsd"); - - /* If there is no thread descriptor there cannot be any thread - specific data. */ - if (th->th_unique == NULL) - return TD_BADKEY; - - /* Get the thread descriptor. */ - if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds, - sizeof (struct _pthread_descr_struct)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Check correct value of key. */ - if (tk >= pthread_keys_max) - return TD_BADKEY; - - /* Get the key entry. */ - if (ps_pdread (th->th_ta_p->ph, &keys[tk], &key, - sizeof (struct pthread_key_struct)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* Fail if this key is not at all used. */ - if (! key.in_use) - return TD_BADKEY; - - /* Compute the indeces. */ - idx1st = tk / pthread_key_2ndlevel_size; - idx2nd = tk % pthread_key_2ndlevel_size; - - /* Check the pointer to the second level array. */ - if (pds.p_specific[idx1st] == NULL) - return TD_NOTSD; - - /* Now get the real key. - XXX I don't know whether it's correct but there is currently no - easy way to determine whether a key was never set or the value - is NULL. We return an error whenever the value is NULL. */ - if (ps_pdread (th->th_ta_p->ph, &pds.p_specific[idx1st][idx2nd], &p, - sizeof (void *)) != PS_OK) - return TD_ERR; - - if (p != NULL) - *data = p; - - return p != NULL ? TD_OK : TD_NOTSD; -} diff --git a/libpthread/linuxthreads_db/td_thr_validate.c b/libpthread/linuxthreads_db/td_thr_validate.c deleted file mode 100644 index e18b5728b..000000000 --- a/libpthread/linuxthreads_db/td_thr_validate.c +++ /dev/null @@ -1,70 +0,0 @@ -/* Validate a thread handle. - Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper , 1999. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include "thread_dbP.h" -#include "../linuxthreads/internals.h" - - -td_err_e -td_thr_validate (const td_thrhandle_t *th) -{ - struct pthread_handle_struct *handles = th->th_ta_p->handles; - int pthread_threads_max = th->th_ta_p->pthread_threads_max; - int cnt; - struct pthread_handle_struct phc; - - LOG ("td_thr_validate"); - - /* A special case: if the program just starts up the handle is - NULL. */ - if (th->th_unique == NULL) - { - /* Read the first handle. If the pointer to the thread - descriptor is not NULL this is an error. */ - if (ps_pdread (th->th_ta_p->ph, handles, &phc, - sizeof (struct pthread_handle_struct)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - return phc.h_descr == NULL ? TD_OK : TD_NOTHR; - } - - /* Now get all descriptors, one after the other. */ - for (cnt = 0; cnt < pthread_threads_max; ++cnt, ++handles) - { - if (ps_pdread (th->th_ta_p->ph, handles, &phc, - sizeof (struct pthread_handle_struct)) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - if (phc.h_descr != NULL && phc.h_descr == th->th_unique) - { - struct _pthread_descr_struct pds; - - if (ps_pdread (th->th_ta_p->ph, phc.h_descr, &pds, - th->th_ta_p->sizeof_descr) != PS_OK) - return TD_ERR; /* XXX Other error value? */ - - /* XXX There should be another test using the TID but this is - currently not available. */ - return pds.p_terminated != 0 ? TD_NOTHR : TD_OK; - } - } - - return TD_ERR; -} diff --git a/libpthread/linuxthreads_db/thread_db.h b/libpthread/linuxthreads_db/thread_db.h deleted file mode 100644 index f0d9aa7c3..000000000 --- a/libpthread/linuxthreads_db/thread_db.h +++ /dev/null @@ -1,451 +0,0 @@ -/* Copyright (C) 1999, 2001, 2002 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _THREAD_DB_H -#define _THREAD_DB_H 1 - -/* This is the debugger interface for the LinuxThreads library. It is - modelled closely after the interface with same names in Solaris with - the goal to share the same code in the debugger. */ -#include -#include -#include -#include - - -/* Error codes of the library. */ -typedef enum -{ - TD_OK, /* No error. */ - TD_ERR, /* No further specified error. */ - TD_NOTHR, /* No matching thread found. */ - TD_NOSV, /* No matching synchronization handle found. */ - TD_NOLWP, /* No matching light-weighted process found. */ - TD_BADPH, /* Invalid process handle. */ - TD_BADTH, /* Invalid thread handle. */ - TD_BADSH, /* Invalid synchronization handle. */ - TD_BADTA, /* Invalid thread agent. */ - TD_BADKEY, /* Invalid key. */ - TD_NOMSG, /* No event available. */ - TD_NOFPREGS, /* No floating-point register content available. */ - TD_NOLIBTHREAD, /* Application not linked with thread library. */ - TD_NOEVENT, /* Requested event is not supported. */ - TD_NOCAPAB, /* Capability not available. */ - TD_DBERR, /* Internal debug library error. */ - TD_NOAPLIC, /* Operation is not applicable. */ - TD_NOTSD, /* No thread-specific data available. */ - TD_MALLOC, /* Out of memory. */ - TD_PARTIALREG, /* Not entire register set was read or written. */ - TD_NOXREGS, /* X register set not available for given thread. */ - TD_NOTALLOC, /* TLS memory not yet allocated. */ - TD_VERSION /* Version if libpthread and libthread_db do not match. */ -} td_err_e; - - -/* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to - select threads regardless of state in td_ta_thr_iter(). */ -typedef enum -{ - TD_THR_ANY_STATE, - TD_THR_UNKNOWN, - TD_THR_STOPPED, - TD_THR_RUN, - TD_THR_ACTIVE, - TD_THR_ZOMBIE, - TD_THR_SLEEP, - TD_THR_STOPPED_ASLEEP -} td_thr_state_e; - -/* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used - to select threads regardless of type in td_ta_thr_iter(). */ -typedef enum -{ - TD_THR_ANY_TYPE, - TD_THR_USER, - TD_THR_SYSTEM -} td_thr_type_e; - - -/* Types of the debugging library. */ - -/* Handle for a process. This type is opaque. */ -typedef struct td_thragent td_thragent_t; - -/* The actual thread handle type. This is also opaque. */ -typedef struct td_thrhandle -{ - td_thragent_t *th_ta_p; - psaddr_t th_unique; -} td_thrhandle_t; - - -/* Forward declaration of a type defined by and for the dynamic linker. */ -struct link_map; - - -/* Flags for `td_ta_thr_iter'. */ -#define TD_THR_ANY_USER_FLAGS 0xffffffff -#define TD_THR_LOWEST_PRIORITY -20 -#define TD_SIGNO_MASK NULL - - -#define TD_EVENTSIZE 2 -#define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */ -#define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */ -#define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */ - -/* Bitmask of enabled events. */ -typedef struct td_thr_events -{ - uint32_t event_bits[TD_EVENTSIZE]; -} td_thr_events_t; - -/* Event set manipulation macros. */ -#define __td_eventmask(n) \ - (UINT32_C (1) << (((n) - 1) & BT_UIMASK)) -#define __td_eventword(n) \ - ((UINT32_C ((n) - 1)) >> BT_UISHIFT) - -#define td_event_emptyset(setp) \ - do { \ - int __i; \ - for (__i = TD_EVENTSIZE; __i > 0; --__i) \ - (setp)->event_bits[__i - 1] = 0; \ - } while (0) - -#define td_event_fillset(setp) \ - do { \ - int __i; \ - for (__i = TD_EVENTSIZE; __i > 0; --__i) \ - (setp)->event_bits[__i - 1] = UINT32_C (0xffffffff); \ - } while (0) - -#define td_event_addset(setp, n) \ - (((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n)) -#define td_event_delset(setp, n) \ - (((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n)) -#define td_eventismember(setp, n) \ - (__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)])) -#if TD_EVENTSIZE == 2 -# define td_eventisempty(setp) \ - (!((setp)->event_bits[0]) && !((setp)->event_bits[1])) -#else -# error "td_eventisempty must be changed to match TD_EVENTSIZE" -#endif - -/* Events reportable by the thread implementation. */ -typedef enum -{ - TD_ALL_EVENTS, /* Pseudo-event number. */ - TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */ - TD_READY, /* Is executable now. */ - TD_SLEEP, /* Blocked in a synchronization obj. */ - TD_SWITCHTO, /* Now assigned to a process. */ - TD_SWITCHFROM, /* Not anymore assigned to a process. */ - TD_LOCK_TRY, /* Trying to get an unavailable lock. */ - TD_CATCHSIG, /* Signal posted to the thread. */ - TD_IDLE, /* Process getting idle. */ - TD_CREATE, /* New thread created. */ - TD_DEATH, /* Thread terminated. */ - TD_PREEMPT, /* Preempted. */ - TD_PRI_INHERIT, /* Inherited elevated priority. */ - TD_REAP, /* Reaped. */ - TD_CONCURRENCY, /* Number of processes changing. */ - TD_TIMEOUT, /* Conditional variable wait timed out. */ - TD_MIN_EVENT_NUM = TD_READY, - TD_MAX_EVENT_NUM = TD_TIMEOUT, - TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */ -} td_event_e; - -/* Values representing the different ways events are reported. */ -typedef enum -{ - NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */ - NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically - inserted. */ - NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */ -} td_notify_e; - -/* Description how event type is reported. */ -typedef struct td_notify -{ - td_notify_e type; /* Way the event is reported. */ - union - { - psaddr_t bptaddr; /* Address of breakpoint. */ - int syscallno; /* Number of system call used. */ - } u; -} td_notify_t; - -/* Structure used to report event. */ -typedef struct td_event_msg -{ - td_event_e event; /* Event type being reported. */ - const td_thrhandle_t *th_p; /* Thread reporting the event. */ - union - { -# if 0 - td_synchandle_t *sh; /* Handle of synchronization object. */ -#endif - uintptr_t data; /* Event specific data. */ - } msg; -} td_event_msg_t; - -/* Structure containing event data available in each thread structure. */ -typedef struct -{ - td_thr_events_t eventmask; /* Mask of enabled events. */ - td_event_e eventnum; /* Number of last event. */ - void *eventdata; /* Data associated with event. */ -} td_eventbuf_t; - - -/* Gathered statistics about the process. */ -typedef struct td_ta_stats -{ - int nthreads; /* Total number of threads in use. */ - int r_concurrency; /* Concurrency level requested by user. */ - int nrunnable_num; /* Average runnable threads, numerator. */ - int nrunnable_den; /* Average runnable threads, denominator. */ - int a_concurrency_num; /* Achieved concurrency level, numerator. */ - int a_concurrency_den; /* Achieved concurrency level, denominator. */ - int nlwps_num; /* Average number of processes in use, - numerator. */ - int nlwps_den; /* Average number of processes in use, - denominator. */ - int nidle_num; /* Average number of idling processes, - numerator. */ - int nidle_den; /* Average number of idling processes, - denominator. */ -} td_ta_stats_t; - - -/* Since Sun's library is based on Solaris threads we have to define a few - types to map them to POSIX threads. */ -typedef pthread_t thread_t; -typedef pthread_key_t thread_key_t; - - -/* Callback for iteration over threads. */ -typedef int td_thr_iter_f (const td_thrhandle_t *, void *); - -/* Callback for iteration over thread local data. */ -typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *); - - - -/* Forward declaration. This has to be defined by the user. */ -struct ps_prochandle; - - -/* Information about the thread. */ -typedef struct td_thrinfo -{ - td_thragent_t *ti_ta_p; /* Process handle. */ - unsigned int ti_user_flags; /* Unused. */ - thread_t ti_tid; /* Thread ID returned by - pthread_create(). */ - char *ti_tls; /* Pointer to thread-local data. */ - psaddr_t ti_startfunc; /* Start function passed to - pthread_create(). */ - psaddr_t ti_stkbase; /* Base of thread's stack. */ - long int ti_stksize; /* Size of thread's stack. */ - psaddr_t ti_ro_area; /* Unused. */ - int ti_ro_size; /* Unused. */ - td_thr_state_e ti_state; /* Thread state. */ - unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */ - td_thr_type_e ti_type; /* Type of the thread (system vs - user thread). */ - intptr_t ti_pc; /* Unused. */ - intptr_t ti_sp; /* Unused. */ - short int ti_flags; /* Unused. */ - int ti_pri; /* Thread priority. */ - lwpid_t ti_lid; /* Unused. */ - sigset_t ti_sigmask; /* Signal mask. */ - unsigned char ti_traceme; /* Nonzero if event reporting - enabled. */ - unsigned char ti_preemptflag; /* Unused. */ - unsigned char ti_pirecflag; /* Unused. */ - sigset_t ti_pending; /* Set of pending signals. */ - td_thr_events_t ti_events; /* Set of enabled events. */ -} td_thrinfo_t; - - - -/* Prototypes for exported library functions. */ - -/* Initialize the thread debug support library. */ -extern td_err_e td_init (void); - -/* Historical relict. Should not be used anymore. */ -extern td_err_e td_log (void); - -/* Return list of symbols the library can request. */ -extern const char **td_symbol_list (void); - -/* Generate new thread debug library handle for process PS. */ -extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta); - -/* Free resources allocated for TA. */ -extern td_err_e td_ta_delete (td_thragent_t *__ta); - -/* Get number of currently running threads in process associated with TA. */ -extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np); - -/* Return process handle passed in `td_ta_new' for process associated with - TA. */ -extern td_err_e td_ta_get_ph (const td_thragent_t *__ta, - struct ps_prochandle **__ph); - -/* Map thread library handle PT to thread debug library handle for process - associated with TA and store result in *TH. */ -extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt, - td_thrhandle_t *__th); - -/* Map process ID LWPID to thread debug library handle for process - associated with TA and store result in *TH. */ -extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid, - td_thrhandle_t *__th); - - -/* Call for each thread in a process associated with TA the callback function - CALLBACK. */ -extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta, - td_thr_iter_f *__callback, void *__cbdata_p, - td_thr_state_e __state, int __ti_pri, - sigset_t *__ti_sigmask_p, - unsigned int __ti_user_flags); - -/* Call for each defined thread local data entry the callback function KI. */ -extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki, - void *__p); - - -/* Get event address for EVENT. */ -extern td_err_e td_ta_event_addr (const td_thragent_t *__ta, - td_event_e __event, td_notify_t *__ptr); - -/* Enable EVENT in global mask. */ -extern td_err_e td_ta_set_event (const td_thragent_t *__ta, - td_thr_events_t *__event); - -/* Disable EVENT in global mask. */ -extern td_err_e td_ta_clear_event (const td_thragent_t *__ta, - td_thr_events_t *__event); - -/* Return information about last event. */ -extern td_err_e td_ta_event_getmsg (const td_thragent_t *__ta, - td_event_msg_t *__msg); - - -/* Set suggested concurrency level for process associated with TA. */ -extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level); - - -/* Enable collecting statistics for process associated with TA. */ -extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable); - -/* Reset statistics. */ -extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta); - -/* Retrieve statistics from process associated with TA. */ -extern td_err_e td_ta_get_stats (const td_thragent_t *__ta, - td_ta_stats_t *__statsp); - - -/* Validate that TH is a thread handle. */ -extern td_err_e td_thr_validate (const td_thrhandle_t *__th); - -/* Return information about thread TH. */ -extern td_err_e td_thr_get_info (const td_thrhandle_t *__th, - td_thrinfo_t *__infop); - -/* Retrieve floating-point register contents of process running thread TH. */ -extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th, - prfpregset_t *__regset); - -/* Retrieve general register contents of process running thread TH. */ -extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th, - prgregset_t __gregs); - -/* Retrieve extended register contents of process running thread TH. */ -extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs); - -/* Get size of extended register set of process running thread TH. */ -extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep); - -/* Set floating-point register contents of process running thread TH. */ -extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th, - const prfpregset_t *__fpregs); - -/* Set general register contents of process running thread TH. */ -extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th, - prgregset_t __gregs); - -/* Set extended register contents of process running thread TH. */ -extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th, - const void *__addr); - - -/* Get address of thread local variable. */ -extern td_err_e td_thr_tls_get_addr (const td_thrhandle_t *__th, - void *__map_address, size_t __offset, - void **__address); - - -/* Enable reporting for EVENT for thread TH. */ -extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event); - -/* Enable EVENT for thread TH. */ -extern td_err_e td_thr_set_event (const td_thrhandle_t *__th, - td_thr_events_t *__event); - -/* Disable EVENT for thread TH. */ -extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th, - td_thr_events_t *__event); - -/* Get event message for thread TH. */ -extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th, - td_event_msg_t *__msg); - - -/* Set priority of thread TH. */ -extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio); - - -/* Set pending signals for thread TH. */ -extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th, - unsigned char __n, const sigset_t *__ss); - -/* Set signal mask for thread TH. */ -extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th, - const sigset_t *__ss); - - -/* Return thread local data associated with key TK in thread TH. */ -extern td_err_e td_thr_tsd (const td_thrhandle_t *__th, - const thread_key_t __tk, void **__data); - - -/* Suspend execution of thread TH. */ -extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th); - -/* Resume execution of thread TH. */ -extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th); - -#endif /* thread_db.h */ diff --git a/libpthread/linuxthreads_db/thread_dbP.h b/libpthread/linuxthreads_db/thread_dbP.h deleted file mode 100644 index c45336ac9..000000000 --- a/libpthread/linuxthreads_db/thread_dbP.h +++ /dev/null @@ -1,110 +0,0 @@ -/* Private header for thread debug library. */ -#ifndef _THREAD_DBP_H -#define _THREAD_DBP_H 1 - -#define __FORCE_GLIBC -#include -#include -#include -#include "proc_service.h" -#include "thread_db.h" -#include "../linuxthreads/internals.h" - - -/* Indeces for the symbol names. */ -enum - { - PTHREAD_THREADS_EVENTS = 0, - PTHREAD_LAST_EVENT, - PTHREAD_HANDLES_NUM, - PTHREAD_HANDLES, - PTHREAD_KEYS, - LINUXTHREADS_PTHREAD_THREADS_MAX, - LINUXTHREADS_PTHREAD_KEYS_MAX, - LINUXTHREADS_PTHREAD_SIZEOF_DESCR, - LINUXTHREADS_CREATE_EVENT, - LINUXTHREADS_DEATH_EVENT, - LINUXTHREADS_REAP_EVENT, - LINUXTHREADS_INITIAL_REPORT_EVENTS, - LINUXTHREADS_VERSION, - NUM_MESSAGES - }; - - -/* Comment out the following for less verbose output. */ -#ifndef NDEBUG -# define LOG(c) if (__td_debug) __libc_write (2, c "\n", strlen (c "\n")) -extern int __td_debug; -#else -# define LOG(c) -#endif - - -/* Handle for a process. This type is opaque. */ -struct td_thragent -{ - /* Delivered by the debugger and we have to pass it back in the - proc callbacks. */ - struct ps_prochandle *ph; - - /* Some cached information. */ - - /* Address of the `__pthread_handles' array. */ - struct pthread_handle_struct *handles; - - /* Address of the `pthread_kyes' array. */ - struct pthread_key_struct *keys; - - /* Maximum number of threads. */ - int pthread_threads_max; - - /* Maximum number of thread-local data keys. */ - int pthread_keys_max; - - /* Size of 2nd level array for thread-local data keys. */ - int pthread_key_2ndlevel_size; - - /* Sizeof struct _pthread_descr_struct. */ - int sizeof_descr; - - /* Pointer to the `__pthread_threads_events' variable in the target. */ - psaddr_t pthread_threads_eventsp; - - /* Pointer to the `__pthread_last_event' variable in the target. */ - psaddr_t pthread_last_event; - - /* Pointer to the `__pthread_handles_num' variable. */ - psaddr_t pthread_handles_num; -}; - - -/* Type used internally to keep track of thread agent descriptors. */ -struct agent_list -{ - td_thragent_t *ta; - struct agent_list *next; -}; - -/* List of all known descriptors. */ -extern struct agent_list *__td_agent_list; - -/* Function used to test for correct thread agent pointer. */ -static inline int -ta_ok (const td_thragent_t *ta) -{ - struct agent_list *runp = __td_agent_list; - - if (ta == NULL) - return 0; - - while (runp != NULL && runp->ta != ta) - runp = runp->next; - - return runp != NULL; -} - - -/* Internal wrapper around ps_pglobal_lookup. */ -extern int td_lookup (struct ps_prochandle *ps, int idx, psaddr_t *sym_addr); - -#endif /* thread_dbP.h */ -- cgit v1.2.3