summaryrefslogtreecommitdiffstats
path: root/lib/libc/gen
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2010-09-25 01:57:47 +0000
committerdavidxu <davidxu@FreeBSD.org>2010-09-25 01:57:47 +0000
commit74604ed9c419ab380cacaaeb78e4c26f9f37e0ad (patch)
tree7b4cd520f700d5e2d7a21bc8175c8574d209a3ce /lib/libc/gen
parentdf0d735bfefbd56b7c7cbca4590c651f83e3c831 (diff)
downloadFreeBSD-src-74604ed9c419ab380cacaaeb78e4c26f9f37e0ad.zip
FreeBSD-src-74604ed9c419ab380cacaaeb78e4c26f9f37e0ad.tar.gz
To support stack unwinding for cancellation points, add -fexceptions flag
for them, two functions _pthread_cancel_enter and _pthread_cancel_leave are added to let thread enter and leave a cancellation point, it also makes it possible that other functions can be cancellation points in libraries without having to be rewritten in libthr.
Diffstat (limited to 'lib/libc/gen')
-rw-r--r--lib/libc/gen/Makefile.inc10
-rw-r--r--lib/libc/gen/Symbol.map2
-rw-r--r--lib/libc/gen/_pthread_stubs.c4
-rw-r--r--lib/libc/gen/sem.c31
-rw-r--r--lib/libc/gen/sem_new.c37
5 files changed, 31 insertions, 53 deletions
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index dd4bb5a..32888dd 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -25,7 +25,7 @@ SRCS+= __getosreldate.c __xuname.c \
pause.c pmadvise.c popen.c posix_spawn.c \
psignal.c pututxline.c pw_scan.c pwcache.c \
raise.c readdir.c readpassphrase.c rewinddir.c \
- scandir.c seed48.c seekdir.c sem.c sem_new.c semctl.c \
+ scandir.c seed48.c seekdir.c semctl.c \
setdomainname.c sethostname.c setjmperr.c setmode.c \
setproctitle.c setprogname.c siginterrupt.c siglist.c signal.c \
sigsetops.c sleep.c srand48.c statvfs.c stringlist.c strtofflags.c \
@@ -35,6 +35,14 @@ SRCS+= __getosreldate.c __xuname.c \
usleep.c utime.c utxdb.c valloc.c vis.c wait.c wait3.c waitpid.c \
wordexp.c
+CANCELPOINTS_SRCS=sem.c sem_new.c
+.for src in ${CANCELPOINTS_SRCS}
+SRCS+=cancelpoints_${src}
+CLEANFILES+=cancelpoints_${src}
+cancelpoints_${src}:
+ ln -sf ${.CURDIR}/gen/${src} ${.TARGET}
+.endfor
+
SYM_MAPS+=${.CURDIR}/gen/Symbol.map
# machine-dependent gen sources
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index 6bd3140..dd375b0 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -403,6 +403,8 @@ FBSDprivate_1.0 {
_pthread_attr_setstackaddr;
_pthread_attr_setstacksize;
_pthread_cancel;
+ _pthread_cancel_enter;
+ _pthread_cancel_leave;
_pthread_cleanup_pop;
_pthread_cleanup_push;
_pthread_cond_broadcast;
diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c
index 044e299e..355b904 100644
--- a/lib/libc/gen/_pthread_stubs.c
+++ b/lib/libc/gen/_pthread_stubs.c
@@ -121,6 +121,8 @@ pthread_func_entry_t __thr_jtable[PJT_MAX] = {
{PJT_DUAL_ENTRY(stub_zero)}, /* PJT_TESTCANCEL */
{PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_POP_IMP */
{PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CLEANUP_PUSH_IMP */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CANCEL_ENTER */
+ {PJT_DUAL_ENTRY(stub_zero)}, /* PJT_CANCEL_LEAVE */
};
/*
@@ -269,6 +271,8 @@ STUB_FUNC2(pthread_setcanceltype, PJT_SETCANCELTYPE, int, int, void *)
STUB_FUNC(pthread_testcancel, PJT_TESTCANCEL, void)
STUB_FUNC1(__pthread_cleanup_pop_imp, PJT_CLEANUP_POP_IMP, int, int)
STUB_FUNC2(__pthread_cleanup_push_imp, PJT_CLEANUP_PUSH_IMP, void, void*, void *);
+STUB_FUNC1(_pthread_cancel_enter, PJT_CANCEL_ENTER, int, int)
+STUB_FUNC1(_pthread_cancel_leave, PJT_CANCEL_LEAVE, int, int)
static int
stub_zero(void)
diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c
index 628e650..e9ae669 100644
--- a/lib/libc/gen/sem.c
+++ b/lib/libc/gen/sem.c
@@ -312,21 +312,6 @@ _libc_sem_unlink_compat(const char *name)
}
static int
-enable_async_cancel(void)
-{
- int old;
-
- _pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
- return (old);
-}
-
-static void
-restore_async_cancel(int val)
-{
- _pthread_setcanceltype(val, NULL);
-}
-
-static int
_umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *timeout)
{
if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
@@ -371,15 +356,15 @@ _libc_sem_timedwait_compat(sem_t * __restrict sem,
const struct timespec * __restrict abstime)
{
struct timespec ts, ts2;
- int val, retval, saved_cancel;
+ int val, retval;
if (sem_check_validity(sem) != 0)
return (-1);
if ((*sem)->syssem != 0) {
- saved_cancel = enable_async_cancel();
- retval = ksem_wait((*sem)->semid);
- restore_async_cancel(saved_cancel);
+ _pthread_cancel_enter(1);
+ retval = ksem_wait((*sem)->semid); /* XXX no timeout */
+ _pthread_cancel_leave(retval == -1);
return (retval);
}
@@ -390,8 +375,10 @@ _libc_sem_timedwait_compat(sem_t * __restrict sem,
if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1))
return (0);
}
- if (retval)
+ if (retval) {
+ _pthread_testcancel();
break;
+ }
if (abstime) {
if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) {
errno = EINVAL;
@@ -402,9 +389,9 @@ _libc_sem_timedwait_compat(sem_t * __restrict sem,
}
atomic_add_int(&(*sem)->nwaiters, 1);
pthread_cleanup_push(sem_cancel_handler, sem);
- saved_cancel = enable_async_cancel();
+ _pthread_cancel_enter(1);
retval = _umtx_wait_uint(&(*sem)->count, 0, abstime ? &ts2 : NULL);
- restore_async_cancel(saved_cancel);
+ _pthread_cancel_leave(0);
pthread_cleanup_pop(0);
atomic_add_int(&(*sem)->nwaiters, -1);
}
diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c
index ef4ba68..2698b40 100644
--- a/lib/libc/gen/sem_new.c
+++ b/lib/libc/gen/sem_new.c
@@ -47,6 +47,7 @@
#include <semaphore.h>
#include <unistd.h>
#include "un-namespace.h"
+#include "libc_private.h"
__weak_reference(_sem_close, sem_close);
__weak_reference(_sem_destroy, sem_destroy);
@@ -364,15 +365,6 @@ _sem_trywait(sem_t *sem)
return (-1);
}
-static void
-sem_cancel_handler(void *arg)
-{
- sem_t *sem = arg;
-
- if (sem->_kern._has_waiters && sem->_kern._count)
- usem_wake(&sem->_kern);
-}
-
#define TIMESPEC_SUB(dst, src, val) \
do { \
(dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \
@@ -384,27 +376,12 @@ sem_cancel_handler(void *arg)
} while (0)
-static __inline int
-enable_async_cancel(void)
-{
- int old;
-
- _pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
- return (old);
-}
-
-static __inline void
-restore_async_cancel(int val)
-{
- _pthread_setcanceltype(val, NULL);
-}
-
int
_sem_timedwait(sem_t * __restrict sem,
const struct timespec * __restrict abstime)
{
struct timespec ts, ts2;
- int val, retval, saved_cancel;
+ int val, retval;
if (sem_check_validity(sem) != 0)
return (-1);
@@ -416,8 +393,10 @@ _sem_timedwait(sem_t * __restrict sem,
return (0);
}
- if (retval)
+ if (retval) {
+ _pthread_testcancel();
break;
+ }
/*
* The timeout argument is only supposed to
@@ -431,11 +410,9 @@ _sem_timedwait(sem_t * __restrict sem,
clock_gettime(CLOCK_REALTIME, &ts);
TIMESPEC_SUB(&ts2, abstime, &ts);
}
- pthread_cleanup_push(sem_cancel_handler, sem);
- saved_cancel = enable_async_cancel();
+ _pthread_cancel_enter(1);
retval = usem_wait(&sem->_kern, abstime ? &ts2 : NULL);
- restore_async_cancel(saved_cancel);
- pthread_cleanup_pop(0);
+ _pthread_cancel_leave(0);
}
return (retval);
}
OpenPOWER on IntegriCloud