diff options
29 files changed, 700 insertions, 76 deletions
diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 26b8909e7f..c6047d3b3b 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,56 @@ +2003-06-22 Ulrich Drepper <drepper@redhat.com> + + * pthreadP.h (__pthread_mutex_init_internal): Mark hidden. + (__pthread_mutex_lock_internal): Likewise. + (__pthread_mutex_unlock_internal): Likewise. + (__pthread_mutex_unlock_usercnt): Declare. + * pthread_mutex_destroy.c: Always fail if used in any way. + * pthread_mutex_init.c: Update comment. + * pthread_mutex_lock.c: If NO_INCR is not defined adjust __nusers. + * pthread_mutex_timedlock.c: Adjust __nusers. + * pthread_mutex_trylock.c: Adjust __nusers. + * pthread_mutex_unlock.c: Old code is in __pthread_mutex_unlock_usercnt + and public interfaces are wrapper with pass additional parameter. + __pthread_mutex_unlock_usercnt does not adjust __nusers if second + parameter zero. + * tst-mutex8.c: New file. + * Makefile (tests): Add tst-mutex8. + * sysdeps/pthread/pthread_cond_timedwait.c: Call + __pthread_mutex_unlock_usercnt. + * sysdeps/pthread/pthread_cond_wait.c: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S: Likewise. + * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise. + * sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c: Define NO_INCR. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t): + Add __nusers. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + + * pthread_mutex_lock.c: Don't store THREAD_ID in __owner, use TID. + * pthread_mutex_timedlock.c: Likewise. + * pthread_mutex_trylock.c: Adjust __nusers. + * pthread_mutex_unlock.c: Compare with TID not THREAD_ID. + * tst-mutex9.c: New file. + * Makefile (tests): Add tst-mutex9. + * sysdeps/i386/tls.h: Remove THREAD_ID definition. + * sysdeps/ia64/tls.h: Likewise. + * sysdeps/powerpc/tls.h: Likewise. + * sysdeps/s390/tls.h: Likewise. + * sysdeps/sh/tls.h: Likewise. + * sysdeps/x86_64/tls.h: Likewise. + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_mutex_t): + Change type of __owner. + * sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h: Likewise. + * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: Likewise. + 2003-06-19 Jakub Jelinek <jakub@redhat.com> * sysdeps/unix/sysv/linux/ia64/sem_post.c: Move to... diff --git a/nptl/Makefile b/nptl/Makefile index 349f3ac312..a6aa8c2666 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -187,7 +187,7 @@ omit-deps = $(unix-syscalls:%=ptw-%) tests = tst-attr1 tst-attr2 \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ - tst-mutex7 \ + tst-mutex7 tst-mutex8 tst-mutex9 \ tst-spin1 tst-spin2 tst-spin3 \ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \ tst-cond8 tst-cond9 tst-cond10 tst-cond11 \ diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c index dec390c552..91ccfb0d29 100644 --- a/nptl/pthread_mutex_destroy.c +++ b/nptl/pthread_mutex_destroy.c @@ -25,9 +25,7 @@ int __pthread_mutex_destroy (mutex) pthread_mutex_t *mutex; { - if (__builtin_expect (mutex->__data.__kind == PTHREAD_MUTEX_ERRORCHECK_NP, - 0) - && lll_mutex_trylock (mutex->__data.__lock) != 0) + if (mutex->__data.__nusers != 0) return EBUSY; return 0; diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c index 038e09d008..a95f97ad4f 100644 --- a/nptl/pthread_mutex_init.c +++ b/nptl/pthread_mutex_init.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -48,7 +48,8 @@ __pthread_mutex_init (mutex, mutexattr) /* Default values: mutex not used yet. */ // mutex->__count = 0; already done by memset - // mutex->__owner = NULL; already done by memset + // mutex->__owner = 0; already done by memset + // mutex->__nusers = 0; already done by memset return 0; } diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c index 4fdb13718c..9c61aa75f6 100644 --- a/nptl/pthread_mutex_lock.c +++ b/nptl/pthread_mutex_lock.c @@ -31,7 +31,7 @@ int __pthread_mutex_lock (mutex) pthread_mutex_t *mutex; { - struct pthread *id = THREAD_ID; + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) { @@ -55,6 +55,9 @@ __pthread_mutex_lock (mutex) /* Record the ownership. */ mutex->__data.__owner = id; mutex->__data.__count = 1; +#ifndef NO_INCR + ++mutex->__data.__nusers; +#endif } break; @@ -74,6 +77,9 @@ __pthread_mutex_lock (mutex) LLL_MUTEX_LOCK (mutex->__data.__lock); /* Record the ownership. */ mutex->__data.__owner = id; +#ifndef NO_INCR + ++mutex->__data.__nusers; +#endif break; } diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index f24f91dd3c..8efc422042 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -27,7 +27,7 @@ pthread_mutex_timedlock (mutex, abstime) pthread_mutex_t *mutex; const struct timespec *abstime; { - struct pthread *id = THREAD_ID; + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); int result = 0; /* We must not check ABSTIME here. If the thread does not block @@ -80,8 +80,11 @@ pthread_mutex_timedlock (mutex, abstime) } if (result == 0) - /* Record the ownership. */ - mutex->__data.__owner = id; + { + /* Record the ownership. */ + mutex->__data.__owner = id; + ++mutex->__data.__nusers; + } out: return result; diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c index c61d7d5852..b164e0205e 100644 --- a/nptl/pthread_mutex_trylock.c +++ b/nptl/pthread_mutex_trylock.c @@ -26,12 +26,13 @@ int __pthread_mutex_trylock (mutex) pthread_mutex_t *mutex; { - struct pthread *id = THREAD_ID; + pid_t *id; switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) { /* Recursive mutex. */ case PTHREAD_MUTEX_RECURSIVE_NP: + id = THREAD_GETMEM (THREAD_SELF, tid); /* Check whether we already hold the mutex. */ if (mutex->__data.__owner == id) { @@ -49,6 +50,7 @@ __pthread_mutex_trylock (mutex) /* Record the ownership. */ mutex->__data.__owner = id; mutex->__data.__count = 1; + ++mutex->__data.__nusers; return 0; } break; @@ -63,7 +65,8 @@ __pthread_mutex_trylock (mutex) if (lll_mutex_trylock (mutex->__data.__lock) == 0) { /* Record the ownership. */ - mutex->__data.__owner = id; + mutex->__data.__owner = THREAD_GETMEM (THREAD_SELF, tid); + ++mutex->__data.__nusers; return 0; } diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c index 975127d2b2..56b1cd4a9a 100644 --- a/nptl/pthread_mutex_unlock.c +++ b/nptl/pthread_mutex_unlock.c @@ -23,14 +23,16 @@ int -__pthread_mutex_unlock (mutex) +internal_function +__pthread_mutex_unlock_usercnt (mutex, decr) pthread_mutex_t *mutex; + bool decr; { switch (__builtin_expect (mutex->__data.__kind, PTHREAD_MUTEX_TIMED_NP)) { case PTHREAD_MUTEX_RECURSIVE_NP: /* Recursive mutex. */ - if (mutex->__data.__owner != THREAD_ID) + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid)) return EPERM; if (--mutex->__data.__count != 0) @@ -40,7 +42,7 @@ __pthread_mutex_unlock (mutex) case PTHREAD_MUTEX_ERRORCHECK_NP: /* Error checking mutex. */ - if (mutex->__data.__owner != THREAD_ID + if (mutex->__data.__owner != THREAD_GETMEM (THREAD_SELF, tid) || ! lll_mutex_islocked (mutex->__data.__lock)) return EPERM; break; @@ -54,12 +56,23 @@ __pthread_mutex_unlock (mutex) } /* Always reset the owner field. */ - mutex->__data.__owner = NULL; + mutex->__data.__owner = 0; + if (decr) + /* One less user. */ + --mutex->__data.__nusers; /* Unlock. */ lll_mutex_unlock (mutex->__data.__lock); return 0; } + + +int +__pthread_mutex_unlock (mutex) + pthread_mutex_t *mutex; +{ + return __pthread_mutex_unlock_usercnt (mutex, true); +} strong_alias (__pthread_mutex_unlock, pthread_mutex_unlock) strong_alias (__pthread_mutex_unlock, __pthread_mutex_unlock_internal) diff --git a/nptl/sysdeps/i386/tls.h b/nptl/sysdeps/i386/tls.h index e0fc9ee284..85d6473380 100644 --- a/nptl/sysdeps/i386/tls.h +++ b/nptl/sysdeps/i386/tls.h @@ -248,13 +248,9 @@ union user_desc_init # define THREAD_SELF \ ({ struct pthread *__self; \ asm ("movl %%gs:%c1,%0" : "=r" (__self) \ - : "i" (offsetof (struct pthread, header.self))); \ + : "i" (offsetof (struct pthread, header.self))); \ __self;}) -/* Identifier for the current thread. THREAD_SELF is usable but - sometimes more expensive than necessary. It is fine here. */ -# define THREAD_ID THREAD_SELF - /* Read member of the thread descriptor directly. */ # define THREAD_GETMEM(descr, member) \ diff --git a/nptl/sysdeps/ia64/tls.h b/nptl/sysdeps/ia64/tls.h index 5ce74737a7..8a13a59d30 100644 --- a/nptl/sysdeps/ia64/tls.h +++ b/nptl/sysdeps/ia64/tls.h @@ -113,10 +113,6 @@ register struct pthread *__thread_self __asm__("r13"); /* Return the thread descriptor for the current thread. */ # define THREAD_SELF (__thread_self - 1) -/* Identifier for the current thread. THREAD_SELF is usable but - sometimes more expensive than necessary as in this case. */ -# define THREAD_ID __thread_self - /* Access to data in the thread descriptor is easy. */ #define THREAD_GETMEM(descr, member) \ descr->member diff --git a/nptl/sysdeps/powerpc/tls.h b/nptl/sysdeps/powerpc/tls.h index 70aff09e24..6573bb6b04 100644 --- a/nptl/sysdeps/powerpc/tls.h +++ b/nptl/sysdeps/powerpc/tls.h @@ -129,10 +129,6 @@ register void *__thread_register __asm__ ("r13"); ((struct pthread *) (__thread_register \ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE)) -/* Identifier for the current thread. THREAD_SELF is usable but - sometimes more expensive than necessary as in this case. */ -# define THREAD_ID __thread_register - /* Read member of the thread descriptor directly. */ # define THREAD_GETMEM(descr, member) ((void)(descr), (THREAD_SELF)->member) diff --git a/nptl/sysdeps/pthread/pthread_cond_timedwait.c b/nptl/sysdeps/pthread/pthread_cond_timedwait.c index 4dd6f2e02a..7f7d2086f2 100644 --- a/nptl/sysdeps/pthread/pthread_cond_timedwait.c +++ b/nptl/sysdeps/pthread/pthread_cond_timedwait.c @@ -56,7 +56,7 @@ __pthread_cond_timedwait (cond, mutex, abstime) lll_mutex_lock (cond->__data.__lock); /* Now we can release the mutex. */ - int err = __pthread_mutex_unlock_internal (mutex); + int err = __pthread_mutex_unlock_usercnt (mutex, 0); if (err) { lll_mutex_unlock (cond->__data.__lock); diff --git a/nptl/sysdeps/pthread/pthread_cond_wait.c b/nptl/sysdeps/pthread/pthread_cond_wait.c index da94cc2d6b..75edf3d158 100644 --- a/nptl/sysdeps/pthread/pthread_cond_wait.c +++ b/nptl/sysdeps/pthread/pthread_cond_wait.c @@ -82,7 +82,7 @@ __pthread_cond_wait (cond, mutex) lll_mutex_lock (cond->__data.__lock); /* Now we can release the mutex. */ - err = __pthread_mutex_unlock_internal (mutex); + err = __pthread_mutex_unlock_usercnt (mutex, 0); if (err) { lll_mutex_unlock (cond->__data.__lock); diff --git a/nptl/sysdeps/s390/tls.h b/nptl/sysdeps/s390/tls.h index 89e51ff228..06237ae15b 100644 --- a/nptl/sysdeps/s390/tls.h +++ b/nptl/sysdeps/s390/tls.h @@ -137,10 +137,6 @@ typedef struct /* Return the thread descriptor for the current thread. */ # define THREAD_SELF ((struct pthread *) __builtin_thread_pointer ()) -/* Identifier for the current thread. THREAD_SELF is usable but - sometimes more expensive than necessary. It is fine here. */ -# define THREAD_ID THREAD_SELF - /* Access to data in the thread descriptor is easy. */ #define THREAD_GETMEM(descr, member) \ descr->member diff --git a/nptl/sysdeps/sh/tls.h b/nptl/sysdeps/sh/tls.h index a6cefa0b31..1e27b987e0 100644 --- a/nptl/sysdeps/sh/tls.h +++ b/nptl/sysdeps/sh/tls.h @@ -117,13 +117,6 @@ typedef struct __asm ("stc gbr,%0" : "=r" (__self)); \ __self - 1;}) -/* Identifier for the current thread. THREAD_SELF is usable but - sometimes more expensive than necessary as in this case. */ -# define THREAD_ID \ - ({ struct pthread *__self; \ - __asm ("stc gbr,%0" : "=r" (__self)); \ - __self;}) - /* Read member of the thread descriptor directly. */ # define THREAD_GETMEM(descr, member) (descr->member) diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h index 256589da0d..a098106629 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h @@ -51,10 +51,11 @@ typedef union { int __lock; unsigned int __count; - struct pthread *__owner; + int __owner; /* KIND must stay at this position in the structure to maintain binary compatibility. */ int __kind; + unsigned int __nusers; } __data; char __size[__SIZEOF_PTHREAD_MUTEX_T]; long int __align; diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S index 5eec268b29..2f598980e5 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S @@ -72,9 +72,8 @@ __pthread_cond_timedwait: movl %eax, dep_mutex(%ebx) /* Unlock the mutex. */ - pushl %eax -.Lpush4: - call __pthread_mutex_unlock_internal + xorl %edx, %edx + call __pthread_mutex_unlock_usercnt testl %eax, %eax jne 16f @@ -90,7 +89,7 @@ __pthread_cond_timedwait: #else leal __condvar_cleanup, %eax #endif - subl $40, %esp + subl $44, %esp .Lsubl: leal 28(%esp), %edx movl %esp, 8(%esp) @@ -299,15 +298,15 @@ __pthread_cond_timedwait: /* The initial unlocking of the mutex failed. */ 16: .LSbl3: - movl %eax, (%esp) LOCK #if cond_lock == 0 subl $1, (%ebx) #else subl $1, cond_lock(%ebx) #endif - jne 17f + jne 18b + movl %eax, %esi #if cond_lock == 0 movl %ebx, %eax #else @@ -315,7 +314,7 @@ __pthread_cond_timedwait: #endif call __lll_mutex_unlock_wake -17: popl %eax + movl %esi, %eax jmp 18b #if defined __NR_clock_gettime && !defined __ASSUME_POSIX_TIMERS @@ -411,10 +410,8 @@ versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, .uleb128 20 .byte 0x83 # DW_CFA_offset %ebx .uleb128 5 - .byte 0x40+.Lpush4-.Lpush_ebx # DW_CFA_advance_loc+N - .byte 14 # DW_CFA_def_cfa_offset - .uleb128 24 - .byte 0x40+.Lsubl-.Lpush4 # DW_CFA_advance_loc+N + .byte 2 # DW_CFA_advance_loc1 + .byte .Lsubl-.Lpush_ebx .byte 14 # DW_CFA_def_cfa_offset .uleb128 64 .byte 3 # DW_CFA_advance_loc2 diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S index 61d3d8d225..c98899ab05 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S @@ -127,9 +127,8 @@ __pthread_cond_wait: movl %eax, dep_mutex(%ebx) /* Unlock the mutex. */ - pushl %eax -.Lpush4: - call __pthread_mutex_unlock_internal + xorl %edx, %edx + call __pthread_mutex_unlock_usercnt testl %eax, %eax jne 12f @@ -145,7 +144,7 @@ __pthread_cond_wait: #else leal __condvar_cleanup, %eax #endif - subl $32, %esp + subl $36, %esp .Lsubl: leal 20(%esp), %edx movl %esp, 8(%esp) @@ -289,15 +288,15 @@ __pthread_cond_wait: /* The initial unlocking of the mutex failed. */ 12: .LSbl3: - movl %eax, (%esp) LOCK #if cond_lock == 0 subl $1, (%ebx) #else subl $1, cond_lock(%ebx) #endif - jne 13f + jne 14b + movl %eax, %esi #if cond_lock == 0 movl %ebx, %eax #else @@ -305,7 +304,7 @@ __pthread_cond_wait: #endif call __lll_mutex_unlock_wake -13: popl %eax + movl %esi, %eax jmp 14b .LENDCODE: .size __pthread_cond_wait, .-__pthread_cond_wait @@ -371,10 +370,8 @@ versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, .uleb128 16 .byte 0x83 # DW_CFA_offset %ebx .uleb128 4 - .byte 0x40+.Lpush4-.Lpush_ebx # DW_CFA_advance_loc+N - .byte 14 # DW_CFA_def_cfa_offset - .uleb128 20 - .byte 0x40+.Lsubl-.Lpush4 # DW_CFA_advance_loc+N + .byte 2 # DW_CFA_advance_loc1 + .byte .Lsubl-.Lpush_ebx .byte 14 # DW_CFA_def_cfa_offset .uleb128 52 .byte 2 # DW_CFA_advance_loc1 diff --git a/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h index afd2f31465..c1eca62be7 100644 --- a/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/ia64/bits/pthreadtypes.h @@ -51,7 +51,8 @@ typedef union { int __lock; unsigned int __count; - struct pthread *__owner; + int __owner; + unsigned int __nusers; /* KIND must stay at this position in the structure to maintain binary compatibility. */ int __kind; diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h index 8f3e64d75b..f827b3098d 100644 --- a/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/powerpc/bits/pthreadtypes.h @@ -66,10 +66,16 @@ typedef union { int __lock; unsigned int __count; - struct pthread *__owner; + int __owner; +#if __WORDSIZE == 64 + unsigned int __nusers; +#endif /* KIND must stay at this position in the structure to maintain binary compatibility. */ int __kind; +#if __WORDSIZE != 64 + unsigned int __nusers; +#endif } __data; char __size[__SIZEOF_PTHREAD_MUTEX_T]; long int __align; diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c b/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c index 893a5e932d..d253c72ea4 100644 --- a/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c +++ b/nptl/sysdeps/unix/sysv/linux/pthread_mutex_cond_lock.c @@ -2,5 +2,6 @@ #define LLL_MUTEX_LOCK(mutex) lll_mutex_cond_lock(mutex) #define __pthread_mutex_lock __pthread_mutex_cond_lock +#define NO_INCR #include <nptl/pthread_mutex_lock.c> diff --git a/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h index e34875f996..2d37683ee2 100644 --- a/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/s390/bits/pthreadtypes.h @@ -65,10 +65,16 @@ typedef union { int __lock; unsigned int __count; - struct pthread *__owner; + int __owner; +#if __WORDSIZE == 64 + unsigned int __nusers; +#endif /* KIND must stay at this position in the structure to maintain binary compatibility. */ int __kind; +#if __WORDSIZE != 64 + unsigned int __nusers; +#endif } __data; char __size[__SIZEOF_PTHREAD_MUTEX_T]; long int __align; diff --git a/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h index 1eeae708e1..8236fd724a 100644 --- a/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/sh/bits/pthreadtypes.h @@ -52,10 +52,11 @@ typedef union { int __lock; unsigned int __count; - struct pthread *__owner; + int __owner; /* KIND must stay at this position in the structure to maintain binary compatibility. */ int __kind; + unsigned int __nusers; } __data; char __size[__SIZEOF_PTHREAD_MUTEX_T]; long int __align; diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h index b2919ab4c6..ed3050e636 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h @@ -51,7 +51,8 @@ typedef union { int __lock; unsigned int __count; - struct pthread *__owner; + int __owner; + unsigned int __nusers; /* KIND must stay at this position in the structure to maintain binary compatibility. */ int __kind; diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S index b64953ba83..b2b4449554 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_timedwait.S @@ -91,7 +91,8 @@ __pthread_cond_timedwait: /* Unlock the mutex. */ 2: movq 16(%rsp), %rdi - callq __pthread_mutex_unlock_internal + xorq %rsi, %rsi + callq __pthread_mutex_unlock_usercnt testl %eax, %eax jne 16f diff --git a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S index 2c6c6ce338..3942faf1ad 100644 --- a/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S +++ b/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S @@ -136,7 +136,8 @@ __pthread_cond_wait: /* Unlock the mutex. */ 2: movq 16(%rsp), %rdi - callq __pthread_mutex_unlock_internal + xorq %rsi, %rsi + callq __pthread_mutex_unlock_usercnt testl %eax, %eax jne 12f diff --git a/nptl/sysdeps/x86_64/tls.h b/nptl/sysdeps/x86_64/tls.h index 973b242b4e..999c3aa55a 100644 --- a/nptl/sysdeps/x86_64/tls.h +++ b/nptl/sysdeps/x86_64/tls.h @@ -161,10 +161,6 @@ typedef struct : "i" (offsetof (struct pthread, header.self))); \ __self;}) -/* Identifier for the current thread. THREAD_SELF is usable but - sometimes more expensive than necessary. It is fine here. */ -# define THREAD_ID THREAD_SELF - /* Read member of the thread descriptor directly. */ # define THREAD_GETMEM(descr, member) \ diff --git a/nptl/tst-mutex8.c b/nptl/tst-mutex8.c new file mode 100644 index 0000000000..80ebe71f0c --- /dev/null +++ b/nptl/tst-mutex8.c @@ -0,0 +1,367 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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. */ + +/* This test checks behavior not required by POSIX. */ +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t *m; +static pthread_barrier_t b; +static pthread_cond_t c; +static bool done; + + +static void +cl (void *arg) +{ + if (pthread_mutex_unlock (m) != 0) + { + puts ("cl: mutex_unlocked failed"); + exit (1); + } +} + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (m) != 0) + { + puts ("tf: mutex_lock failed"); + return (void *) 1l; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return (void *) 1l; + } + + if (arg == NULL) + do + if (pthread_cond_wait (&c, m) != 0) + { + puts ("tf: cond_wait failed"); + return (void *) 1l; + } + while (! done); + else + do + { + pthread_cleanup_push (cl, NULL); + + if (pthread_cond_wait (&c, m) != 0) + { + puts ("tf: cond_wait failed"); + return (void *) 1l; + } + + pthread_cleanup_pop (0); + } + while (! done); + + if (pthread_mutex_unlock (m) != 0) + { + puts ("tf: mutex_unlock failed"); + return (void *) 1l; + } + + return NULL; +} + + +static int +check_type (const char *mas, pthread_mutexattr_t *ma) +{ + if (pthread_mutex_init (m, ma) != 0) + { + printf ("1st mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("immediate mutex_destroy failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_init (m, ma) != 0) + { + printf ("2nd mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + printf ("1st mutex_lock failed for %s\n", mas); + return 1; + } + + int e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("mutex_destroy of self-locked mutex did not return EBUSY %s\n", + mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("1st mutex_unlock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_trylock (m) != 0) + { + printf ("mutex_trylock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of self-trylocked mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +mutex_destroy of self-trylocked mutex did not return EBUSY %s\n", + mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("2nd mutex_unlock failed for %s\n", mas); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("1st create failed"); + return 1; + } + done = false; + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + printf ("2nd mutex_lock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("3rd mutex_unlock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of condvar-used mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas); + return 1; + } + + done = true; + if (pthread_cond_signal (&c) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + if (r != NULL) + { + puts ("thread didn't return NULL"); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("mutex_destroy after condvar-use failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_init (m, ma) != 0) + { + printf ("3rd mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_create (&th, NULL, tf, (void *) 1) != 0) + { + puts ("2nd create failed"); + return 1; + } + done = false; + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("2nd barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + printf ("3rd mutex_lock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("4th mutex_unlock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("2nd mutex_destroy of condvar-used mutex succeeded for %s\n", + mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +2nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", + mas); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cond_cancel failed"); + return 1; + } + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("mutex_destroy after condvar-canceled failed for %s\n", mas); + return 1; + } + + return 0; +} + + +static int +do_test (void) +{ + pthread_mutex_t mm; + m = &mm; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_cond_init (&c, NULL) != 0) + { + puts ("cond_init failed"); + return 1; + } + + puts ("check normal mutex"); + int res = check_type ("normal", NULL); + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("1st mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE) != 0) + { + puts ("1st mutexattr_settype failed"); + return 1; + } + puts ("check recursive mutex"); + res |= check_type ("recursive", &ma); + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("1st mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("2nd mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("2nd mutexattr_settype failed"); + return 1; + } + puts ("check error-checking mutex"); + res |= check_type ("error-checking", &ma); + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("2nd mutexattr_destroy failed"); + return 1; + } + + return res; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/nptl/tst-mutex9.c b/nptl/tst-mutex9.c new file mode 100644 index 0000000000..94e993c5cb --- /dev/null +++ b/nptl/tst-mutex9.c @@ -0,0 +1,194 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ +#if ! _POSIX_THREAD_PROCESS_SHARED + + puts ("_POSIX_THREAD_PROCESS_SHARED not supported, test skipped"); + return 0; + +#else + + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-mutex9.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutex_t *m; + pthread_mutexattr_t a; + pid_t pid; + char *p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + p = (char *) (m + 1); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + if (pthread_mutex_trylock (m) == 0) + { + puts ("child: mutex_trylock succeeded"); + exit (1); + } + + if (pthread_mutex_unlock (m) == 0) + { + puts ("child: mutex_unlock succeeded"); + exit (1); + } + + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ++ts.tv_sec; + ts.tv_nsec -= 1000000000; + } + + int e = pthread_mutex_timedlock (m, &ts); + if (e == 0) + { + puts ("child: mutex_timedlock succeeded"); + exit (1); + } + if (e != ETIMEDOUT) + { + puts ("child: mutex_timedlock didn't time out"); + exit (1); + } + + alarm (1); + + pthread_mutex_lock (m); + + puts ("child: mutex_lock returned"); + + exit (0); + } + + sleep (2); + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + if (! WIFSIGNALED (status)) + { + puts ("child not killed by signal"); + return 1; + } + if (WTERMSIG (status) != SIGALRM) + { + puts ("child not killed by SIGALRM"); + return 1; + } + + return 0; +#endif +} + +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |