Bug 111538
Summary: | pthread canceltype changed after cancellation while blocked in a syscall | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Product: | [Retired] Red Hat Linux | Reporter: | Davide Guerri <tatonet> | ||||||||
Component: | glibc | Assignee: | Jakub Jelinek <jakub> | ||||||||
Status: | CLOSED NOTABUG | QA Contact: | Brian Brock <bbrock> | ||||||||
Severity: | medium | Docs Contact: | |||||||||
Priority: | medium | ||||||||||
Version: | 9 | CC: | drepper, fweimer | ||||||||
Target Milestone: | --- | ||||||||||
Target Release: | --- | ||||||||||
Hardware: | i386 | ||||||||||
OS: | Linux | ||||||||||
Whiteboard: | |||||||||||
Fixed In Version: | Doc Type: | Bug Fix | |||||||||
Doc Text: | Story Points: | --- | |||||||||
Clone Of: | Environment: | ||||||||||
Last Closed: | 2003-12-08 09:43:17 UTC | Type: | --- | ||||||||
Regression: | --- | Mount Type: | --- | ||||||||
Documentation: | --- | CRM: | |||||||||
Verified Versions: | Category: | --- | |||||||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||||||
Cloudforms Team: | --- | Target Upstream Version: | |||||||||
Embargoed: | |||||||||||
Attachments: |
|
Description
Davide Guerri
2003-12-04 22:53:17 UTC
Created attachment 96357 [details]
Test program for the bug.
Created attachment 96358 [details]
Test program for the bug.
And where exactly does the POSIX specification support this claim of yours? Temporary workarounds: void __resetCancelType(void *dummy) { pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); } unsigned int ef_sleep(unsigned int seconds) { unsigned int retVal; pthread_cleanup_push(__resetCancelType, NULL); retVal = sleep(seconds); pthread_cleanup_pop(0); return retVal; } int ef_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec *abstime) { int retVal; pthread_cleanup_push(__resetCancelType, NULL); retVal = pthread_cond_timedwait(cond, mutex, abstime); pthread_cleanup_pop(1); return retVal; } [...] I'm not sure that posix specifies anyting about it, but the behaviour should be the same always, while the problem doesn't appear when blocked in pthread_cond_wait() (for instance) And what about the behaviour of the thread when leaving timedwait after a signal? (I know my English is horrible, but let me try to explain this) If POSIX doesn't specify anything about the cancellation type after a cancel, and you decided to set it to PTHREAD_CANCEL_ASYNCHRONOUS, there is a problem: If one calls pthread_exit() the cancellation type remain unchanged while the execution of cleanup handlers. If the cleanup handler is executed due to a pthread_cancel() while we're blocked in a syscall, the cancellation type change to asynchronous. The pthread_cancel() man page says that pthread_cancel() should have the same effect of a call to pthread_exit(PTHREAD_CANCELED). (Is this a POSIX specification?) If a developer can't know if the cleanup handler is called due to a cancellation or a pthread_exit() (and therefore the cancellation type of the thread is unknown) he/she can't make any assumption. Test program that exibit the behaviour i stated above. On my system the output is this: --------------------------------------- [tato@Gohan a]$ ./double_cancel 1) Beacause in cleanup handler we invoke a syscall, the handler is executed two times: cleanup handler (begin) cancel type = asynchronous cleanup handler (end) cleanup handler (begin) cancel type = asynchronous cleanup handler (end) 2) This time the thread calls pthread_exit(PTHREAD_CANCELED) and the cleanup handler is executed three times. Moreover the first execution is interrupted by the second: cleanup handler (begin) cancel type = deferred cleanup handler (begin) cancel type = asynchronous cleanup handler (end) cleanup handler (begin) cancel type = asynchronous cleanup handler (end) Bye! --------------------------------------- This example arises another problem: how many times a cleanup handler will be executed? Will it be interrupted and restarted in case of cancellation (see step 2) )? If the behaviour were "unspecified" the documentation should state that one could not use syscalls in (or as) cleanup handlers. But in the pthread_cleanup_push() man page is stated: <<Cleanup handlers can be used similarly to free blocks allocated with malloc(3) or close file descriptors on thread termination.>> Unfortunately close() is a syscall... I know that this problem is solved using "pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate)" in the handler, but what if we use directly a library function (that invoke internally a syscall) for cleanup handler? Created attachment 96367 [details]
Test program for the bug.
In reply to Ulrich Drepper. In the rationale section http://www.opengroup.org/onlinepubs/007904975/functions/pthread_setcancelstate.html says: <<...the cancelability type may be explicitly set to either deferred or asynchronous upon entry to an object. But as with the cancelability state, on exit from an object the cancelability type should always be restored to its value on entry to the object.>> Moreover, http://www.opengroup.org/onlinepubs/007904975/functions/pthread_cleanup_pop.html in the description section says: << [...] The cancellation cleanup handler shall be popped from the cancellation cleanup stack and invoked with the argument arg when: - The thread exits (that is, calls pthread_exit()). - The thread acts upon a cancellation request. - The thread calls pthread_cleanup_pop() with a non-zero execute argument. [...] >> So a cleanup handler should not be re-executed if a cancellation occours during its execution, because the handler should have been popped. I did a mess with this bug report. Sorry. There is no reason to pretend a predicible canceltype after a cancellation since in cleanup handlers the cancellation should be disabled. Moreover I think that there are two bugs not one: the problem with pthread_cond_timedwait() and the problem with cancellation cleanup handlers. I'll close this report and I'll create two separate (and less messed) bug reports. Sorry again, not "to pretend", "to require"... )); |