From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030922 Description of problem: pthread_mutex_destroy should return EBUSY if the mutex being destroyed is currently locked. If ptread_mutex_unlock is called without calling pthread_mutex_lock, pthread_mutex_destroy in NPTL returns EBUSY. This scenario can happen in cleanup handlers where a mutex is being unlocked when a thread exits. Version-Release number of selected component (if applicable): glibc-2.3.2-95.6, kernel-2.4.21-4.EL, RHE ES 3.0, gcc-3.2.3-20 How reproducible: Always Steps to Reproduce: 1. prog.c: #include <stdio.h> #include <string.h> #include <pthread.h> int main(int argc, char **argv) { pthread_mutex_t mutt; int status; if ((status = pthread_mutex_init(&mutt, NULL)) == 0) { /* call unlock without first locking the mutex */ if ((status = pthread_mutex_unlock(&mutt)) == 0) { /* destroy results in EBUSY... */ if ((status = pthread_mutex_destroy(&mutt)) != 0) { char buf[256]; char *strErr = strerror_r(status, buf, 256); fprintf(stderr, "status=%d, Error: %s\n", status, strErr); } } } return 0; } 2. gcc -o prog prog.c -lpthread Actual Results: ./prog prints "status=16, Error: Device or resource busy". Expected Results: Since the mutex was not locked, pthread_mutex_destroy should have returned 0. Additional info: This happens in NPTL. LinuxThreads returns 0 for the scenario described above. Using tcsh: env LD_ASSUME_KERNEL=2.4.19 prog does not print the EBUSY error.
I don't see anything wrong about this behaviour. http://www.opengroup.org/onlinepubs/007904975/functions/pthread_mutex_trylock.html says clearly that this program has undefined behaviour. Returning EBUSY from pthread_mutex_destroy on such a mutex is a conforming behaviour. You can use PTHREAD_MUTEX_ERRORCHECK mutex if you want to get an error from pthread_mutex_unlock and not undefined behaviour.
However, http://www.opengroup.org/onlinepubs/007904975/functions/pthread_mutex_destroy.html indicates: "It shall be safe to destroy an initialized mutex that is unlocked. Attempting to destroy a locked mutex results in undefined behavior." In the example, the mutex is not locked. Also: "[EBUSY] The implementation has detected an attempt to destroy the object referenced by mutex while it is locked or referenced (for example, while being used in a pthread_cond_timedwait() or pthread_cond_wait()) by another thread." The mutex in the example is neither locked nor referenced by another thread. EBUSY shouldn't be returned in this case...
That doesn't matter. Once your program hits undefined behaviour once, the standard doesn't cover anything in it any more. The implementation may choose to lock a mutex in pthread_mutex_unlock called on an unlocked mutex, format your disk or whatever else it decides.
You have put the mutex in an undefined state by incorrectly calling pthread_mutex_unlock. Anything can happen after that. Stop arguing that you are so innocent and the bad implementation should help you poor developer. It's your fault alone, live with the consequences. If you cannot write correct code, use the error checking mutex type.
Ulrich: The code given to you is a sample for reproducing the case and I am not arguing anything here. I was just pointing out what the spec says. Mutex unlocks are done in cleanup handlers so that an exiting thread, that hit a cancellation point, doesn't leave it locked. David Butenhof's book describes this mechanism in detail in Chapter 5 page 147!!! Your response here and elsewhere on the web are always rude and obnoxious. Looks like you get angry when someone points out problems in your poorly written code!!! You talk about bad implementation? You should start with NPTL because any reasonable implementation would have basic checks before putting a resource in a funny condition. Your stance is that if the "spec" doesn't say something - do something crazy (like format your disk - Thanks Jakub...)
POSIX specifically has error checking mutexes which are supposed to do basic checks while normal mutexes are not required to do them for performance reasons. Slowing down all conforming code out there because of a few buggy programs is a bad idea. BTW: You can also use PTHREAD_MUTEX_RECURSIVE, which is required similarly to PTHREAD_MUTEX_ERRORCHECK to fail pthread_mutex_unlock if called on unlocked mutex. Mutex unlock in cleanup handlers can be written so that you never unlock an unlocked mutex.
I am not implying that normal mutexes do more error checks in pthread_mutex_unlock. Getting an EBUSY led us down the path of trying to figure out where we were destroying a locked mutex when the problem was of a different nature with an extra pthread_mutex_unlock of an unlocked mutex. This was the right behavior for a normal mutex but the error code is misleading. In glibc's pthread_mutex_unlock.c, mutex->__data.__nusers becomes UINT_MAX when decremented from a value of 0 and pthread_mutex_destroy.c reports an EBUSY because mutex->__data.__nusers is ! 0. Would it make sense to prevent mutex->__data.__nusers from being decremented when it is zero? This way you don't break compliance with the spec, the error codes will be correct and undefined behaviors will remain what they are. This is just a suggestion since our code doesn't rely on this behavior...