about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-04-17 13:21:13 -0400
committerRich Felker <dalias@aerifal.cx>2011-04-17 13:21:13 -0400
commitebf82447be4b30bedc19ad868c3a0662b1ba596d (patch)
tree014a9584255a078cee6c99704306287ab13791f8
parent02eff258c6a39746db287e20c142153e80c81bac (diff)
downloadmusl-ebf82447be4b30bedc19ad868c3a0662b1ba596d.tar.gz
musl-ebf82447be4b30bedc19ad868c3a0662b1ba596d.tar.xz
musl-ebf82447be4b30bedc19ad868c3a0662b1ba596d.zip
optimize cancellation enable/disable code
the goal is to be able to use pthread_setcancelstate internally in
the implementation, whenever a function might want to use functions
which are cancellation points but avoid becoming a cancellation point
itself. i could have just used a separate internal function for
temporarily inhibiting cancellation, but the solution in this commit
is better because (1) it's one less implementation-specific detail in
functions that need to use it, and (2) application code can also get
the same benefit.

previously, pthread_setcancelstate dependend on pthread_self, which
would pull in unwanted thread setup overhead for non-threaded
programs. now, it temporarily stores the state in the global libc
struct if threads have not been initialized, and later moves it if
needed. this way we can instead use __pthread_self, which has no
dependencies and assumes that the thread register is already valid.
-rw-r--r--src/internal/libc.h1
-rw-r--r--src/thread/pthread_self.c1
-rw-r--r--src/thread/pthread_setcancelstate.c11
-rw-r--r--src/thread/pthread_setcanceltype.c2
4 files changed, 11 insertions, 4 deletions
diff --git a/src/internal/libc.h b/src/internal/libc.h
index 3f1e55e5..d6df93d0 100644
--- a/src/internal/libc.h
+++ b/src/internal/libc.h
@@ -16,6 +16,7 @@ struct __libc {
 	volatile int threads_minus_1;
 	int ofl_lock;
 	FILE *ofl_head;
+	int canceldisable;
 };
 
 
diff --git a/src/thread/pthread_self.c b/src/thread/pthread_self.c
index 83efa9e8..e26476ce 100644
--- a/src/thread/pthread_self.c
+++ b/src/thread/pthread_self.c
@@ -14,6 +14,7 @@ static int *errno_location()
 
 static int init_main_thread()
 {
+	main_thread.canceldisable = libc.canceldisable;
 	main_thread.tsd = (void **)__pthread_tsd_main;
 	main_thread.self = &main_thread;
 	if (__set_thread_area(&main_thread) < 0)
diff --git a/src/thread/pthread_setcancelstate.c b/src/thread/pthread_setcancelstate.c
index aa0ddcdd..6722541a 100644
--- a/src/thread/pthread_setcancelstate.c
+++ b/src/thread/pthread_setcancelstate.c
@@ -2,9 +2,14 @@
 
 int pthread_setcancelstate(int new, int *old)
 {
-	struct pthread *self = pthread_self();
-	if (old) *old = self->canceldisable;
 	if (new > 1U) return EINVAL;
-	self->canceldisable = new;
+	if (libc.lock) {
+		struct pthread *self = __pthread_self();
+		if (old) *old = self->canceldisable;
+		self->canceldisable = new;
+	} else {
+		if (old) *old = libc.canceldisable;
+		libc.canceldisable = new;
+	}
 	return 0;
 }
diff --git a/src/thread/pthread_setcanceltype.c b/src/thread/pthread_setcanceltype.c
index c73db22f..7eb543a8 100644
--- a/src/thread/pthread_setcanceltype.c
+++ b/src/thread/pthread_setcanceltype.c
@@ -3,8 +3,8 @@
 int pthread_setcanceltype(int new, int *old)
 {
 	struct pthread *self = pthread_self();
+	if (new > 1U) return EINVAL;
 	if (old) *old = self->cancelasync;
-	if ((unsigned)new > 1) return EINVAL;
 	self->cancelasync = new;
 	return 0;
 }