[PATCH] allow cancellation in pselect() (from kevent())

64 views
Skip to first unread message

Eric Wong

unread,
Apr 26, 2012, 7:31:39 PM4/26/12
to libk...@googlegroups.com
Since pselect() may sleep for long periods of time, temporarily
re-enable cancellation if kevent() is called with cancellation
enabled. This allows threads sleeping in pselect() to be
cancelled in a timely fashion.
---
This patch is also available for download at:
http://bogomips.org/libkqueue.git/patch/?id=5fd5f63afb

src/common/kevent.c | 23 ++++++++--
src/common/private.h | 2 +
src/posix/kevent.c | 9 ++++
test/main.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 152 insertions(+), 3 deletions(-)

diff --git a/src/common/kevent.c b/src/common/kevent.c
index a4c8c25..ba76acd 100644
--- a/src/common/kevent.c
+++ b/src/common/kevent.c
@@ -33,6 +33,23 @@
#include "sys/event.h"
#include "private.h"

+static int __thread kq_cancelstate;
+
+void kevent_tmp_cancel_enable(void)
+{
+ if (kq_cancelstate == PTHREAD_CANCEL_ENABLE) {
+ int tmpcancelstate;
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &tmpcancelstate);
+ assert(tmpcancelstate == PTHREAD_CANCEL_DISABLE);
+ }
+}
+
+void kevent_tmp_cancel_disable(void)
+{
+ if (kq_cancelstate == PTHREAD_CANCEL_ENABLE)
+ (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+}
+
static char *
kevent_filter_dump(const struct kevent *kev)
{
@@ -238,7 +255,7 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges,
const struct timespec *timeout)
{
struct kqueue *kq;
- int rv, n, nret, cancelstate;
+ int rv, n, nret;

nret = 0;

@@ -248,7 +265,7 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges,
return (-1);
}

- if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate) != 0)
+ if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &kq_cancelstate) != 0)
return (-1);

kqueue_lock(kq);
@@ -321,7 +338,7 @@ errout:
out:
kqueue_unlock(kq);
kqueue_put(kq);
- (void) pthread_setcancelstate(cancelstate, NULL);
+ (void) pthread_setcancelstate(kq_cancelstate, NULL);
pthread_testcancel();
return (nret);
}
diff --git a/src/common/private.h b/src/common/private.h
index f0f06a2..992c89a 100644
--- a/src/common/private.h
+++ b/src/common/private.h
@@ -196,6 +196,8 @@ int kevent_wait(struct kqueue *, const struct timespec *);
int kevent_copyout(struct kqueue *, int, struct kevent *, int);
void kevent_free(struct kqueue *);
const char *kevent_dump(const struct kevent *);
+void kevent_tmp_cancel_enable(void);
+void kevent_tmp_cancel_disable(void);

struct kqueue * kqueue_get(int);
void kqueue_put(struct kqueue *);
diff --git a/src/posix/kevent.c b/src/posix/kevent.c
index d521029..125959a 100644
--- a/src/posix/kevent.c
+++ b/src/posix/kevent.c
@@ -32,7 +32,16 @@ kevent_wait(struct kqueue *kq, const struct timespec *timeout)

dbg_puts("waiting for events");
kqueue_unlock(kq);
+
+ pthread_cleanup_push((void *)kqueue_put, kq);
+ kevent_tmp_cancel_enable();
+
+ /* pselect() is a cancellation point */
n = pselect(nfds, &rfds, NULL , NULL, timeout, NULL);
+
+ kevent_tmp_cancel_disable();
+ pthread_cleanup_pop(0); /* no cleanup needed if we didn't get cancelled */
+
if (n < 0) {
dbg_perror("pselect(2)");
if (errno == EINTR)
diff --git a/test/main.c b/test/main.c
index 098a8c4..5db782b 100644
--- a/test/main.c
+++ b/test/main.c
@@ -16,6 +16,8 @@

#include <sys/types.h>
#include <poll.h>
+#include <pthread.h>
+#include <time.h>

#include "common.h"

@@ -103,6 +105,122 @@ test_ev_receipt(void)
#endif
}

+static void
+test_cancel_state_unchanged(void)
+{
+ int kq, rc, state;
+ struct timespec ts = { 0, 1000 };
+ struct kevent kev;
+
+ if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) != 0)
+ err(rc, "pthread_setcancelstate");
+
+ if ((kq = kqueue()) < 0)
+ die("kqueue()");
+
+ if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state)) != 0)
+ err(rc, "pthread_setcancelstate");
+ if (state != PTHREAD_CANCEL_ENABLE)
+ die("kqueue() changed cancel state");
+
+ if ((rc = kevent(kq, NULL, 0, &kev, 1, &ts)) != 0)
+ err(rc, "kevent");
+
+ if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state)) != 0)
+ err(rc, "pthread_setcancelstate");
+ if (state != PTHREAD_CANCEL_ENABLE)
+ die("kevent() changed cancel state");
+
+ close(kq);
+}
+
+
+static void *
+thr_cancel_enabled(void *arg)
+{
+ int *kq = arg;
+ struct kevent kev;
+ struct timespec ts = { 100, 0 };
+
+ (void)kevent(*kq, NULL, 0, &kev, 1, &ts);
+
+ die("should never get here due to cancel");
+ return NULL;
+}
+
+static void
+test_cancel_enabled(void)
+{
+ int kq, rc;
+ pthread_t thr;
+ void *retval = NULL;
+ time_t cancelled_at;
+
+ if ((kq = kqueue()) < 0)
+ die("kqueue()");
+
+ if ((rc = pthread_create(&thr, NULL, thr_cancel_enabled, &kq)) != 0)
+ err(rc, "pthread_create");
+
+ cancelled_at = time(NULL);
+ if ((rc = pthread_cancel(thr)) != 0)
+ err(rc, "pthread_cancel");
+ if ((rc = pthread_join(thr, &retval)) != 0)
+ err(rc, "pthread_join");
+ if (retval != PTHREAD_CANCELED)
+ die("thread not cancelled");
+
+ if ((time(NULL) - cancelled_at) > 5)
+ die("cancellation took too long");
+
+ close(kq);
+}
+
+static void *
+thr_cancel_disabled(void *arg)
+{
+ int *kq = arg;
+ struct kevent kev;
+ struct timespec ts = { 1, 0 };
+ int rc, state;
+
+ if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)) != 0)
+ err(rc, "pthread_setcancelstate");
+
+ if ((rc = kevent(*kq, NULL, 0, &kev, 1, &ts)) != 0)
+ err(rc, "kevent");
+
+ if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state)) != 0)
+ err(rc, "pthread_setcancelstate");
+
+ if (state != PTHREAD_CANCEL_DISABLE)
+ die("kevent() didn't preserve pthread cancel state");
+
+ return NULL; /* success */
+}
+
+static void
+test_cancel_disabled(void)
+{
+ int kq, rc;
+ pthread_t thr;
+ void *retval = NULL;
+
+ if ((kq = kqueue()) < 0)
+ die("kqueue()");
+
+ if ((rc = pthread_create(&thr, NULL, thr_cancel_disabled, &kq)) != 0)
+ err(rc, "pthread_create");
+ if ((rc = pthread_cancel(thr)) != 0)
+ err(rc, "pthread_cancel");
+ if ((rc = pthread_join(thr, &retval)) != 0)
+ err(rc, "pthread_join");
+ if (retval != NULL)
+ die("thread not cancelled");
+
+ close(kq);
+}
+
int
main(int argc, char **argv)
{
@@ -156,6 +274,9 @@ main(int argc, char **argv)

test(kqueue);
test(kevent);
+ test(cancel_state_unchanged);
+ test(cancel_enabled);
+ test(cancel_disabled);

if ((kqfd = kqueue()) < 0)
die("kqueue()");
--
Eric Wong

Mark Heily

unread,
Apr 28, 2012, 11:41:41 AM4/28/12
to libk...@googlegroups.com
On 04/26/2012 07:31 PM, Eric Wong wrote:
> Since pselect() may sleep for long periods of time, temporarily
> re-enable cancellation if kevent() is called with cancellation
> enabled. This allows threads sleeping in pselect() to be
> cancelled in a timely fashion.

This has been committed in r547.

I added equivalent behavior for Solaris, and removed the assertion from
kevent_tmp_cancel_enable(). See below for details.

Thanks!

- Mark


> ---
> This patch is also available for download at:
> http://bogomips.org/libkqueue.git/patch/?id=5fd5f63afb
>
> src/common/kevent.c | 23 ++++++++--
> src/common/private.h | 2 +
> src/posix/kevent.c | 9 ++++
> test/main.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 152 insertions(+), 3 deletions(-)
>
> diff --git a/src/common/kevent.c b/src/common/kevent.c
> index a4c8c25..ba76acd 100644
> --- a/src/common/kevent.c
> +++ b/src/common/kevent.c
> @@ -33,6 +33,23 @@
> #include "sys/event.h"
> #include "private.h"
>
> +static int __thread kq_cancelstate;
> +
> +void kevent_tmp_cancel_enable(void)
> +{
> + if (kq_cancelstate == PTHREAD_CANCEL_ENABLE) {
> + int tmpcancelstate;
> + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &tmpcancelstate);
> + assert(tmpcancelstate == PTHREAD_CANCEL_DISABLE);
> + }

This assertion seems unnecessary, because we call
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) earlier in kevent(), and
check the return value.

> +}
> +
> +void kevent_tmp_cancel_disable(void)
> +{
> + if (kq_cancelstate == PTHREAD_CANCEL_ENABLE)
> + (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
> +}
> +
> static char *
> kevent_filter_dump(const struct kevent *kev)
> {
> @@ -238,7 +255,7 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges,
> const struct timespec *timeout)
> {
> struct kqueue *kq;
> - int rv, n, nret, cancelstate;
> + int rv, n, nret;
>
> nret = 0;
>
> @@ -248,7 +265,7 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges,
> return (-1);
> }
>
> - if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate) != 0)
> + if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &kq_cancelstate) != 0)
> return (-1);
>

I think it is safe to assume that kq_cancelstate is PTHREAD_CANCEL_DISABLE
from this point on.

Mark Heily

unread,
Apr 28, 2012, 12:54:37 PM4/28/12
to libk...@googlegroups.com
On 04/26/2012 07:31 PM, Eric Wong wrote:
> +static void *
> +thr_cancel_enabled(void *arg)
> +{
> + int *kq = arg;
> + struct kevent kev;
> + struct timespec ts = { 100, 0 };
> +
> + (void)kevent(*kq, NULL, 0, &kev, 1, &ts);
> +
> + die("should never get here due to cancel");
> + return NULL;
> +}

This test hangs on FreeBSD, and fails when I run it under truss or gdb.. see
below for the output. It looks like kevent() returns EINTR when the thread is
cancelled, instead of actually cancelling the thread. I will test on a few
more platforms, but if this is true, the behavior of libkqueue will have to be
changed to match the BSD implementation.

- Mark

$ gdb ./kqtest
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "amd64-marcel-freebsd"...
(gdb) r
Starting program: /usr/home/mheily/proj/libkqueue/test/kqtest
[New LWP 100562]
[New Thread 801007400 (LWP 100562/kqtest)]
1: test_peer_close_detection()
2: test_kqueue()
3: test_kevent()
4: test_cancel_state_unchanged()
5: test_cancel_enabled()
[New Thread 801007800 (LWP 100575/kqtest)]
thr_cancel_enabled(): should never get here due to cancel: Interrupted system call

Program received signal SIGABRT, Aborted.
[Switching to Thread 801007800 (LWP 100575/kqtest)]
0x0000000800cd0a7c in thr_kill () from /lib/libc.so.7
(gdb) bt
#0 0x0000000800cd0a7c in thr_kill () from /lib/libc.so.7
#1 0x0000000800d6dd3b in abort () from /lib/libc.so.7
#2 0x0000000000401bbe in thr_cancel_enabled (arg=Could not find the frame
base for "thr_cancel_enabled".
) at main.c:147
#3 0x0000000800859274 in pthread_getprio () from /lib/libthr.so.3
#4 0x0000000000000000 in ?? ()
Error accessing memory address 0x7fffffbfe000: Bad address.
(gdb)


$ truss ./kqtest
mmap(0x0,32768,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34366287872
(0x80063f000)
issetugid(0x800640015,0x800634d7e,0x8008507f0,0x8008507c0,0xb297,0x0) = 0 (0x0)
open("/etc/libmap.conf",O_RDONLY,0666) ERR#2 'No such file or directory'
open("/var/run/ld-elf.so.hints",O_RDONLY,057) = 3 (0x3)
read(3,"Ehnt\^A\0\0\0\M^@\0\0\0-\0\0\0\0"...,128) = 128 (0x80)
lseek(3,0x80,SEEK_SET) = 128 (0x80)
read(3,"/lib:/usr/lib:/usr/lib/compat:/u"...,45) = 45 (0x2d)
close(3) = 0 (0x0)
access("/lib/libthr.so.3",0) = 0 (0x0)
open("/lib/libthr.so.3",O_RDONLY,041037540) = 3 (0x3)
fstat(3,{ mode=-r--r--r-- ,inode=2879,size=101688,blksize=101888 }) = 0 (0x0)
pread(0x3,0x800842f40,0x1000,0x0,0x101010101010101,0x8080808080808080) = 4096
(0x1000)
mmap(0x0,2240512,PROT_NONE,MAP_PRIVATE|MAP_ANON|MAP_NOCORE,-1,0x0) =
34368458752 (0x800851000)
mmap(0x800851000,94208,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_FIXED|MAP_NOCORE,3,0x0)
= 34368458752 (0x800851000)
mmap(0x800a68000,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED,3,0x17000) =
34370650112 (0x800a68000)
mmap(0x800a69000,45056,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED|MAP_ANON,-1,0x0)
= 34370654208 (0x800a69000)
close(3) = 0 (0x0)
access("/lib/librt.so.1",0) ERR#2 'No such file or directory'
access("/usr/lib/librt.so.1",0) = 0 (0x0)
open("/usr/lib/librt.so.1",O_RDONLY,041037540) = 3 (0x3)
fstat(3,{ mode=-r--r--r-- ,inode=2850,size=21744,blksize=22016 }) = 0 (0x0)
pread(0x3,0x800842f40,0x1000,0x0,0x101010101010101,0x8080808080808080) = 4096
(0x1000)
mmap(0x0,2117632,PROT_NONE,MAP_PRIVATE|MAP_ANON|MAP_NOCORE,-1,0x0) =
34370699264 (0x800a74000)
mmap(0x800a74000,20480,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_FIXED|MAP_NOCORE,3,0x0)
= 34370699264 (0x800a74000)
mmap(0x800c78000,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED,3,0x4000) =
34372812800 (0x800c78000)
close(3) = 0 (0x0)
access("/lib/libc.so.7",0) = 0 (0x0)
open("/lib/libc.so.7",O_RDONLY,041037540) = 3 (0x3)
fstat(3,{ mode=-r--r--r-- ,inode=997,size=1315160,blksize=131072 }) = 0 (0x0)
pread(0x3,0x800842f40,0x1000,0x0,0x101010101010101,0x8080808080808080) = 4096
(0x1000)
mmap(0x0,3432448,PROT_NONE,MAP_PRIVATE|MAP_ANON|MAP_NOCORE,-1,0x0) =
34372816896 (0x800c79000)
mmap(0x800c79000,1179648,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_FIXED|MAP_NOCORE,3,0x0)
= 34372816896 (0x800c79000)
mmap(0x800f99000,45056,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED,3,0x120000)
= 34376093696 (0x800f99000)
mmap(0x800fa4000,110592,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED|MAP_ANON,-1,0x0)
= 34376138752 (0x800fa4000)
close(3) = 0 (0x0)
mmap(0x0,40960,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34366320640
(0x800647000)
munmap(0x80064a000,28672) = 0 (0x0)
mmap(0x0,102400,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) =
34366332928 (0x80064a000)
sysarch(0x81,0x7fffffffd340,0x8006431c8,0x0,0xffffffffff6ab080,0x8080808080808080)
= 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
getpid() = 98690 (0x18182)
__sysctl(0x7fffffffd2b0,0x2,0x800a73200,0x7fffffffd2b8,0x0,0x0) = 0 (0x0)
__sysctl(0x7fffffffd1e0,0x2,0x7fffffffd210,0x7fffffffd278,0x800864b70,0xd) = 0
(0x0)
__sysctl(0x7fffffffd210,0x3,0x800a720e8,0x7fffffffd2b8,0x0,0x0) = 0 (0x0)
readlink("/etc/malloc.conf",0x7fffffffcdb0,1024) ERR#2 'No such file or directory'
issetugid(0x800d75bc1,0x7fffffffcdb0,0xffffffffffffffff,0x0,0x2,0x0) = 0 (0x0)
break(0x800000) = 0 (0x0)
mmap(0x0,4194304,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) =
34376249344 (0x800fbf000)
mmap(0x8013bf000,266240,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) =
34380443648 (0x8013bf000)
munmap(0x800fbf000,266240) = 0 (0x0)
thr_self(0x801007400,0x0,0x0,0x0,0x40,0x7fffffffc8e0) = 0 (0x0)
mmap(0x7fffffbfe000,4096,PROT_NONE,MAP_ANON,-1,0x0) = 140737484152832
(0x7fffffbfe000)
rtprio_thread(0x0,0x18895,0x7fffffffd280,0x1000,0xffffffff,0x0) = 0 (0x0)
sysarch(0x81,0x7fffffffd2a0,0x800a71cc0,0x800a72060,0xffffffff,0x0) = 0 (0x0)
sigaction(32,{ 0x80085e200 SA_SIGINFO ss_t },0x0) = 0 (0x0)
sigprocmask(SIG_UNBLOCK,0x0,0x0) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGKILL|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
sigaction(SIGSEGV,{ 0x80085d630 SA_SIGINFO ss_t },{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGKILL|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
sigaction(SIGABRT,{ 0x80085d630 SA_SIGINFO ss_t },{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGKILL|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
sigaction(SIGINT,{ 0x80085d630 SA_SIGINFO ss_t },{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
fstat(1,{ mode=crw--w---- ,inode=123,size=0,blksize=4096 }) = 0 (0x0)
ioctl(1,TIOCGETA,0xffffd450) = 0 (0x0)
1: test_peer_close_detection()
write(1,"1: test_peer_close_detection()\t"...,32) = 32 (0x20)
socketpair(0x1,0x1,0x0,0x7fffffffda00,0x800c1356f,0x7fffffffd89f) = 0 (0x0)
poll({3/POLLIN|POLLHUP},1,0) = 0 (0x0)
close(4) = 0 (0x0)
poll({3/POLLIN|POLLHUP},1,0) = 1 (0x1)
recvfrom(3,0x7fffffffd9ff,1,0x82,NULL,0x0) = 0 (0x0)
2: test_kqueue()
write(1,"2: test_kqueue()\t\n",18) = 18 (0x12)
kqueue(0x0,0x80101a000,0x800faa7a0,0x0,0x800c13561,0x7fffffffd89f) = 4 (0x4)
kevent(4,0x0,0,{},1,{0.000000000 }) = 0 (0x0)
close(4) = 0 (0x0)
3: test_kevent()
write(1,"3: test_kevent()\t\n",18) = 18 (0x12)
kevent(-1,{0x0,0x0,0x0,0,0x0,0x0},1,0x0,0,0x0) ERR#9 'Bad file descriptor'
4: test_cancel_state_unchanged()
write(1,"4: test_cancel_state_unchanged()"...,34) = 34 (0x22)
kqueue(0x0,0x0,0x801007400,0x1,0x800c13571,0x7fffffffd89f) = 4 (0x4)
kevent(4,0x0,0,{},1,{0.000001000 }) = 0 (0x0)
close(4) = 0 (0x0)
5: test_cancel_enabled()
write(1,"5: test_cancel_enabled()\t\n",26) = 26 (0x1a)
kqueue(0x0,0x80101a000,0x800faa7a0,0x0,0x800c13569,0x7fffffffd89f) = 4 (0x4)
_umtx_op(0x7fffffffd8b8,0x3,0x1,0x0,0x0,0x7fffffffd89f) = 0 (0x0)
mprotect(0x0,0,PROT_NONE) = 0 (0x0)
sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGKILL|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
sigprocmask(SIG_SETMASK,0x0,0x0) = 0 (0x0)
mmap(0x0,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34366435328
(0x800663000)
mmap(0x7fffff9fd000,2101248,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_STACK,-1,0x0) =
140737482051584 (0x7fffff9fd000)
mprotect(0x7fffff9fd000,4096,PROT_NONE) = 0 (0x0)
thr_new(0x7fffffffd900,0x68,0x0,0x0,0x0,0x0) = 0 (0x0)
clock_gettime(13,{1335631537.000000000 }) = 0 (0x0)
thr_kill(0x188dd,0x20,0x1,0x0,0x1,0x0) ERR#4 'Interrupted system call'
SIGNAL 32 (?)
sigreturn(0x7fffffbfdb20,0x7fffffbfdb20,0x801007400,0x1,0x0,0x1) ERR#4
'Interrupted system call'
stat("/usr/share/nls/C/libc.cat",0x7fffffbfda20) ERR#2 'No such file or directory'
stat("/usr/share/nls/libc/C",0x7fffffbfda20) ERR#2 'No such file or directory'
stat("/usr/local/share/nls/C/libc.cat",0x7fffffbfda20) ERR#2 'No such file or
directory'
stat("/usr/local/share/nls/libc/C",0x7fffffbfda20) ERR#2 'No such file or
directory'
thr_cancel_enabled(): should never get here due to cancel: Interrupted system call
write(2,"thr_cancel_enabled(): should nev"...,83) = 83 (0x53)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGEMT|SIGFPE|SIGKILL|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
thr_kill(0x188dd,0x6,0x0,0x5,0x7fffff7f7481,0x1) = 0 (0x0)
SIGNAL 6 (SIGABRT)
sigprocmask(SIG_SETMASK,SIGHUP|SIGINT|SIGQUIT|SIGILL|SIGTRAP|SIGABRT|SIGEMT|SIGFPE|SIGBUS|SIGSEGV|SIGSYS|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0)
= 0 (0x0)
***** ERROR: Program received signal 6 *****
write(1,"***** ERROR: Program received si"...,45) = 45 (0x2d)
*** TEST FAILED: (null)
write(1," *** TEST FAILED: (null)\n",25) = 25 (0x19)
process exit, rval = 1

Eric Wong

unread,
Apr 29, 2012, 4:54:10 AM4/29/12
to libk...@googlegroups.com
Mark Heily <ma...@heily.com> wrote:
> On 04/26/2012 07:31 PM, Eric Wong wrote:
> > Since pselect() may sleep for long periods of time, temporarily
> > re-enable cancellation if kevent() is called with cancellation
> > enabled. This allows threads sleeping in pselect() to be
> > cancelled in a timely fashion.
>
> This has been committed in r547.
>
> I added equivalent behavior for Solaris, and removed the assertion from
> kevent_tmp_cancel_enable(). See below for details.

Cool. I wasn't comfortable making the change to the Solaris code since
I don't have an easy way to test that platform. I should've mentioned
that much in my original email :x

> This assertion seems unnecessary, because we call
> pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) earlier in
> kevent(), and check the return value.

I suppose I can be a little paranoid. I'm still new to the code base so
I wanted to be certain I had all my bases covered.

Eric Wong

unread,
Apr 29, 2012, 5:02:34 AM4/29/12
to libk...@googlegroups.com
Mark Heily <ma...@heily.com> wrote:
> This test hangs on FreeBSD, and fails when I run it under truss or gdb.. see
> below for the output. It looks like kevent() returns EINTR when the thread is
> cancelled, instead of actually cancelling the thread. I will test on a few
> more platforms, but if this is true, the behavior of libkqueue will have to be
> changed to match the BSD implementation.

That's a shame.

Any chance we could succesfully lobby the *BSD folks to make kevent() a
cancellation point? It could take a while (and a fair amount of energy,
I'm not familiar with the *BSD communities/processes), but making it a
cancellation point makes a lot of sense to me.

This kevent behavior doesn't affect me or my current project(s) at this
point, but it'd still be a nice-to-have.

Maybe I'll get a pony instead :)
Reply all
Reply to author
Forward
0 new messages