Bug 111538

Summary: pthread canceltype changed after cancellation while blocked in a syscall
Product: [Retired] Red Hat Linux Reporter: Davide Guerri <tatonet>
Component: glibcAssignee: Jakub Jelinek <jakub>
Status: CLOSED NOTABUG QA Contact: Brian Brock <bbrock>
Severity: medium Docs Contact:
Priority: medium    
Version: 9CC: 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 Flags
Test program for the bug.
none
Test program for the bug.
none
Test program for the bug. none

Description Davide Guerri 2003-12-04 22:53:17 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 (compatible; Konqueror/3.1)

Description of problem:
(sorry for my horrible English) 
If a thread is cancelled when is blocked in a syscall or in pthread_cond_timedwait(), its cancellation type is modified in PTHREAD_CANCEL_ASYNCHRONOUS even if its previous type was PTHREAD_CANCEL_DEFERRED. 
The problem verifyes also when pthread_cond_timedwait() is interrupted by a pthread_cond_signal() call.


Version-Release number of selected component (if applicable):
glibc-2.3.2-27.9.7

How reproducible:
Always

Steps to Reproduce:
1. Compile the test programs below
2. Execute the programs
3. Evaluate the results
    

Actual Results:  Before calling sleep() the cancel type of the thread is deferred, after the cancellation, while blocked in sleep(), the cancel type is changed in asynchronous.

Before calling pthread_cond_timedwait() the cancel type of the thread is deferred, after a pthread_cond_signal() the cancel type of the thread is changed in asynchronous.

Expected Results:  In both cases the cancel type should remain deferred.

Additional info:

Comment 1 Davide Guerri 2003-12-04 22:57:23 UTC
Created attachment 96357 [details]
Test program for the bug.

Comment 2 Davide Guerri 2003-12-04 22:59:30 UTC
Created attachment 96358 [details]
Test program for the bug.

Comment 3 Ulrich Drepper 2003-12-04 23:01:48 UTC
And where exactly does the POSIX specification support this claim of
yours?

Comment 4 Davide Guerri 2003-12-04 23:04:34 UTC
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; 
} 
 
[...] 

Comment 5 Davide Guerri 2003-12-04 23:08:16 UTC
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) 

Comment 6 Davide Guerri 2003-12-04 23:10:57 UTC
And what about the behaviour of the thread when leaving timedwait 
after a signal? 

Comment 7 Davide Guerri 2003-12-05 00:50:02 UTC
(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. 
 

Comment 8 Davide Guerri 2003-12-05 09:15:45 UTC
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? 

Comment 9 Davide Guerri 2003-12-05 09:16:38 UTC
Created attachment 96367 [details]
Test program for the bug.

Comment 10 Davide Guerri 2003-12-06 09:27:51 UTC
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.>> 
 

Comment 11 Davide Guerri 2003-12-06 09:42:24 UTC
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. 

Comment 12 Davide Guerri 2003-12-08 09:42:52 UTC
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. 
 

Comment 13 Davide Guerri 2003-12-08 10:02:15 UTC
Sorry again, not "to pretend", "to require"... ));