On Jul 17 17:41, Corinna Vinschen wrote:
> On Jul 17 16:21, Corinna Vinschen wrote:
> > On Jul 17 12:51, Jon Turney wrote:
> > > On 17/07/2023 12:05, Corinna Vinschen wrote:
> > > > diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc
> > > > index f614e01c42f6..fceb9bda1806 100644
> > > > --- a/winsup/cygwin/thread.cc
> > > > +++ b/winsup/cygwin/thread.cc
> > > > @@ -546,6 +546,13 @@ pthread::exit (void *value_ptr)
> > > > class pthread *thread = this;
> > > > _cygtls *tls = cygtls; /* Save cygtls before deleting this. */
> > > > + /* Deferred cancellation still pending? */
> > > > + if (canceled)
> > > > + {
> > > > + WaitForSingleObject (cancel_event, INFINITE);
> > > > + value_ptr = PTHREAD_CANCELED;
> > > > + }
> > > > +
> > > > // run cleanup handlers
> > > > pop_all_cleanup_handlers ();
> > > > What do you think?
> > >
> > > I mean, by your own interpretation of the standard, this isn't required,
> > > because we're allowed to take arbitrarily long to deliver the async
> > > cancellation, and in this case, we took so long that the thread exited
> > > before it happened, too bad...
> >
> > True enough!
> >
> > > It doesn't seem a bad addition,
> >
> Actually, it seems we actually *have* to do this. I just searched
> for more info on that problem and, to my surprise, I found this in the
> most obvious piece of documentation:
>
> https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html
>
> Quote:
>
> As the meaning of the status is determined by the application (except
> when the thread has been canceled, in which case it is
> PTHREAD_CANCELED), [...]
FTR, apparently I have overinterpreted this sentence.
I performed the following crude test on Linux,, the idea being
to call pthread_cancel and then pthread_exit without hitting a
cancallation point in between.
cat > pt.c <<EOF
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
int marker = 0;
void *
thread (void *arg)
{
int oldval;
pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &oldval);
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &oldval);
marker = 1;
while (marker < 2)
;
pthread_exit ((void *) 42);
}
int
main ()
{
int error;
pthread_t pt;
void *retval;
if ((error = pthread_create (&pt, NULL, thread, NULL)))
{
printf ("pthread_create: %d %s\n", error, strerror (error));
return 1;
}
while (marker < 1)
;
if ((error = pthread_cancel (pt)))
{
marker = 2;
printf ("pthread_cancel: %d %s\n", error, strerror (error));
pthread_detach (pt);
return 1;
}
marker = 2;
if ((error = pthread_join (pt, &retval)))
{
printf ("pthread_join: %d %s\n", error, strerror (error));
pthread_detach (pt);
return 1;
}
printf ("retval = %ld (%d)\n", (uintptr_t) retval, retval ==
PTHREAD_CANCELED);
return 0;
}
EOF
$ gcc -g -o pt pt.c -lpthread
$ ./pt
retval = 42 (0)
So retval is the one set by the application, not PTHREAD_CANCELED,
despite the pthread_cancel call. Looks like handling cancellation
inside pthread_exit is really not the right thing to do...
Corinna