Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 30 Nov 2001 17:00:56 -0500
From:      "Louis-Philippe Gagnon" <louisphilippe@macadamian.com>
To:        <freebsd-current@freebsd.org>, <freebsd-hackers@freebsd.org>
Subject:   Possible libc_r pthread bug
Message-ID:  <094601c179ea$7cca85c0$2964a8c0@MACADAMIAN.com>

next in thread | raw e-mail | index | archive | help
If at first you don't succeed...

I've encountered a problem using pthread_cancel, pthread_join and 
pthread_setcanceltype, I'm hoping someone can shed some light.

(in a nutshell : pthread_setcanceltype doesn't seem to work in FreeBSD 4.4)

(posted to -current and -hackers; if there's a more appropriate mailing list 
for this, please let me know)

I recently encountered a situation where, after calling pthread_cancel to 
cancel a thread, the call to pthread_join hangs indefinitely. I quickly figured
out that it was because the thread being cancelled was never reaching a 
cancellation point (in fact it was an infinite loop with no function calls at all). 
Sure enough, adding a pthread_testcancel() in the loop allowed
pthread_join to return. However this solution isn't acceptable for my requirements.

I discovered the pthread_setcanceltype function and its 
PTHREAD_CANCEL_ASYNCHRONOUS parameter, which looked like 
they would give me exactly what I needed : allow threads to be cancelled 
regardless of what they are doing (basically a pthread equivalent to 
TerminateThread).

Unfortunately, my tests have been less than conclusive : pthread_setcanceltype
doesn't seem to do anything at all. It tells me it succeeds, subsequent calls 
properly report the previous cancellation type as ASYNCHRONOUS. 
But pthread_join still hangs, and adding pthread_testcancel calls still 
makes it work...

I'm working on a FreeBSD 4.4-release machine; I ran the same test under 
FreeBSD 4.3-release and got the same results. However, running it on a 
Linux box (Mandrake release, 2.4.x kernel), I get exactly the results I 
was expecting (that is, setting the cancellation type to asynchronous allows
the thread to be cancelled at any time)

see the end of this message for my test program

So the questions are
-am I doing something wrong or misinterpreting the man pages?
-if not, is this a known bug?
-if so, is there a workaround (or is it already fixed)?
-if not, can someone investigate? (I once had a look at the libc_r code 
 and ran away screaming)

If this turns out to be a bug in libc_r, a suggestion for a work-around 
(even a hack) would be much appreciated, even if a proper fix is found and 
committed to CVS (requiring an upgrade from 4.4-release installations is 
something we'd rather avoid).


now for some disclaimers :

I'm aware that asynchronous cancellations (TerminateThread-style) are an 
Evil Thing To Do. Unfortunately I have no choice in the matter.

I'm aware that there are some strict limitations on what a thread is "allowed" 
to do while its cancellation type is asynchronous. specifically, it should only 
call "cancel-safe" functions. Note that in my test program, the thread being 
cancelled doesn't call any functions at all after setting its cancellation type, so 
this shouldn't be an issue.


now for the code :


#include <stdio.h>
#include <pthread.h>

/* thread entry point */
void * thread_entry (void *arg)
{
   int i;

   if(0!=pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL))
   {
      fprintf(stderr,"setcanceltype failed!\n");
   }

   fprintf(stderr,"thread_entry entering loop\n");
   while(1)
   {
      i++;
/* uncomment this to insert a cancellation point */
/*      pthread_testcancel();*/
   }
/* if we see this, it would mean the loop has been optimized out... */
   fprintf(stderr, "after loop\n");
}

int main(void)
{
   pthread_t thread;
   pthread_attr_t attr;
   void *pthread_param;

   pthread_attr_init(&attr);

   fprintf(stderr,"creating thread\n");
   pthread_create(&thread,&attr,&thread_entry,NULL);

   fprintf(stderr,"thread created; hit enter to cancel it...\n");
   getchar();
   fprintf(stderr,"cancelling...\n");
   if(0!=pthread_cancel(thread))
   {
      fprintf(stderr,"cancel failed!\n");
   }
   fprintf(stderr,"after cancel, before join...\n");
   if(0!=pthread_join(thread,&pthread_param))
   {
      fprintf(stderr,"join failed!\n");
   }
   fprintf(stderr,"after join\n");
}

please ask if more details are needed

Thanks in advance,

Louis-Philippe Gagnon ~ louisphilippe@macadamian.com
Macadamian Technologies
"Software experts for the world's leading technology companies."
http://www.macadamian.com



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?094601c179ea$7cca85c0$2964a8c0>