Re: pthread_cancel and cancelation points still broken in Mac OS X 10.5 Leopard?
Re: pthread_cancel and cancelation points still broken in Mac OS X 10.5 Leopard?
- Subject: Re: pthread_cancel and cancelation points still broken in Mac OS X 10.5 Leopard?
- From: Terry Lambert <email@hidden>
- Date: Thu, 22 Nov 2007 12:37:47 -0800
Cancellation passes VSTH test suite conformance testing, and is
therefore compliant with the letter of the specification.
In general, it is implementation defined where uninterruptible
blocking takes place in a given kernel implementation.
If your attemp to explocily cancel is made on a thread whose state is
not blocked in Mach with Mach thread state UNINT, then the action will
be immediate, otherwise, whatever blocking operation must succeed
prior to cancellation.
Another part to this is that it is unspecified in POSIX or the SUS
whether notification operations are synchronous or isochronous or
asynchronous. So, for example, you will not get notification of some
events until you run up to the user/kernel boundary. An example of
this is a signal received during a blocking operation with UNINT set
on a thread, and UNINT not being cleared until the operation has
completed. In this case, the operation (say, read that was waiting on
a disk I/O as a result of a page fault) will complete successfully,
rather than throwing an EINTR error, yet the signal handler also fires.
This type of operation is the same thing you expect on Tru64 UNIX
(also based on Mach), and is likely to become more common as code
paths in kernels become increasingly SMP safe.
So effectively, cancellability in what you've posted as your example
is the same as having lost the scheduler race between the events
preceeding the cancel and the join (I.e.: this I'd exactly how the
code would behave, had the read completed before the cancellation was
attempted).
Without seeing the rest of your code, it's impossible to be more
specific about the race window, but I expect the rout cause is an
assumption about the thread calling the cancel running to completion
without being rescheduled, due to the was the non-"fairness" Linux
sceduler happens to operate, rather than the code being in total
compliance with the spec..
I happen to know the person who will catch this bug report, and unless
you have included a full example that can be compiled to reproduce the
problem, it will bounce back to you as "insufficent information" to
get one. But in any case, I expect the code is at fault here.
-- Terry
On Nov 22, 2007, at 11:11 AM, Per Mildner <email@hidden> wrote:
Sorry if this was the wrong forum for this question, it was not
intended as a complaint or bug report. I hoped some kernel hacker
would be able to shed some light on the technical background to the
implementation of this new and important feature.
I have filed Bug ID# 5610812 for this issue.
Regards,
On Nov 22, 2007, at 7:17 PM, Michael Smith wrote:
Per,
Whilst your complaint may well be legitimate, this is not a bug-
reporting forum.
Please file a bug (bugreporter.apple.com) and include the bug
number when discussing the matter here or (ideally) in any other
forum.
= Mike
On Nov 22, 2007, at 2:41 AM, Per Mildner wrote:
My tests indicate that pthread_cancel still cannot interrupt
blocking system calls like read(2) in Intel Mac OS X 10.5.1,
despite the claim that it is now UNIX 2003 compliant. A brief look
at the Darwin 9.0 kernel sources seems to confirm this.
The Single Unix Specification v3 (SUSv3) defines cancelation
points in
http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_09.html#tag_02_09_05_02
The critical part, and the reason why pthread_testcancel is not
sufficient is "If a thread has cancelability enabled and a
cancellation request is made with the thread as a target while the
thread is suspended at a cancellation point, the thread shall be
awakened and the cancellation request shall be acted upon.". That
is, pthread_cancel should wake (a well defined list of) blocking
system calls.
The below test program shows that a blocking read() is _not_
awakened by pthread_cancel, making the cancelation handling in
Leopard no improvement over earlier OS releases and in violation
of the SUSv3 standard.
The test program starts a worker thread that loops reading from
standard input. The main thread then sleeps for a while to ensure
that the worker thread has blocked in read(2) and the main thread
then cancels the worker thread. This program terminates on Linux
and Solaris but not on Intel Leopard 10.5.1.
From a cursory glance at xnu-1228, e.g. sys_generic.c, it looks as
if the system calls that SUSv3 requires to be cancelation points
are all implemented something like the following template:
int read(...) {
pthread_testcancel();
return read_nocancel(...);
}
That is, if a cancel is pending when the system call is entered
then the call will be canceled but once the real system call is
blocking it will not react to cancel requests.
Transcript:
bash$ gcc cancel_bug.c -Wall && ./a.out
Created thread, sleeping
calling read..<press return>
.called read()==1
calling read..<press return>
.called read()==1
calling read..cancelling read()
<blocks forever or until more input is available>
This is with Xcode 3.0. Compiling with -D_APPLE_C_SOURCE does not
make a difference.
/* cancel_bug.c */
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static int exit_status = EXIT_FAILURE;
#define CHECK(X) do { if ((X) == 0) { fprintf(stderr, "%s:%d CHECK
FAILED\n", __FILE__, (int)__LINE__); } } while (0)
void *
func(void *arg)
{
char buf;
int oldstate;
ssize_t res;
exit_status = EXIT_SUCCESS;
/* redundant */
CHECK(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate) ==
0);
/* Will not terminate unless cancelled or read error */
do
{
fprintf(stderr, "calling read..");fflush(stderr);
res = read(STDIN_FILENO, &buf, 1);
fprintf(stderr, ".called read()==%ld\n", (long)res);fflush
(stderr);
}
while (res != -1);
return NULL;
}
int
main(void)
{
pthread_t thread;
void *retval;
CHECK(pthread_create(&thread, NULL, func, NULL) == 0);
fprintf(stderr, "Created thread, sleeping\n");fflush(stderr);
sleep(10); /* ensure thread reaches blocking read */
fprintf(stderr, "cancelling read()\n");fflush(stderr);
CHECK(pthread_cancel(thread) == 0);
CHECK(pthread_join(thread, &retval) == 0);
CHECK(PTHREAD_CANCELED == retval);
return exit_status;
}
So, has Apple and the Open Group conformance testers made a huge
mistake or am I missing something?
Regards,
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40mu.org
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden