Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libpthread Implement nanosleep() at userlevel. Threaded ...



details:   https://anonhg.NetBSD.org/src/rev/b6cc53882c58
branches:  trunk
changeset: 543061:b6cc53882c58
user:      nathanw <nathanw%NetBSD.org@localhost>
date:      Sat Feb 15 22:15:50 2003 +0000

description:
Implement nanosleep() at userlevel. Threaded applications seem to like
to sleep a lot, and there's no need for each such thread to consume kernel
resources.

(accidentally checked the pthread.c part of this in yesterday; no reason
 not to finish the job)

diffstat:

 lib/libpthread/Makefile             |    3 +-
 lib/libpthread/pthread_cancelstub.c |   18 +---
 lib/libpthread/pthread_sleep.c      |  161 ++++++++++++++++++++++++++++++++++++
 3 files changed, 164 insertions(+), 18 deletions(-)

diffs (228 lines):

diff -r 24852a7f846a -r b6cc53882c58 lib/libpthread/Makefile
--- a/lib/libpthread/Makefile   Sat Feb 15 21:18:59 2003 +0000
+++ b/lib/libpthread/Makefile   Sat Feb 15 22:15:50 2003 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: Makefile,v 1.13 2003/01/24 01:53:27 thorpej Exp $
+#      $NetBSD: Makefile,v 1.14 2003/02/15 22:15:50 nathanw Exp $
 #
 
 WARNS= 2
@@ -49,6 +49,7 @@
 SRCS+= pthread_rwlock.c
 SRCS+= pthread_sa.c
 SRCS+= pthread_sig.c
+SRCS+= pthread_sleep.c
 SRCS+= pthread_specific.c
 SRCS+=  pthread_stack.c
 SRCS+=  pthread_debug.c
diff -r 24852a7f846a -r b6cc53882c58 lib/libpthread/pthread_cancelstub.c
--- a/lib/libpthread/pthread_cancelstub.c       Sat Feb 15 21:18:59 2003 +0000
+++ b/lib/libpthread/pthread_cancelstub.c       Sat Feb 15 22:15:50 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pthread_cancelstub.c,v 1.3 2003/01/27 20:57:41 nathanw Exp $   */
+/*     $NetBSD: pthread_cancelstub.c,v 1.4 2003/02/15 22:15:50 nathanw Exp $   */
 
 /*-
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -69,7 +69,6 @@
 ssize_t        _sys_msgrcv(int, void *, size_t, long, int);
 int    _sys_msgsnd(int, const void *, size_t, int);
 int    _sys___msync13(void *, size_t, int);
-int    _sys_nanosleep(const struct timespec *, struct timespec *);
 int    _sys_open(const char *, int, ...);
 int    _sys_poll(struct pollfd *, nfds_t, int);
 ssize_t        _sys_pread(int, void *, size_t, off_t);
@@ -198,20 +197,6 @@
 }
 
 int
-nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
-{
-       int retval;
-       pthread_t self;
-
-       self = pthread__self();
-       pthread__testcancel(self);
-       retval = _sys_nanosleep(rqtp, rmtp);
-       pthread__testcancel(self);
-
-       return retval;
-}
-
-int
 open(const char *path, int flags, ...)
 {
        int retval;
@@ -362,7 +347,6 @@
 __strong_alias(_msgrcv, msgrcv)
 __strong_alias(_msgsnd, msgsnd)
 __strong_alias(___msync13, __msync13)
-__strong_alias(_nanosleep, nanosleep)
 __strong_alias(_open, open)
 __strong_alias(_poll, poll)
 __strong_alias(_pread, pread)
diff -r 24852a7f846a -r b6cc53882c58 lib/libpthread/pthread_sleep.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libpthread/pthread_sleep.c    Sat Feb 15 22:15:50 2003 +0000
@@ -0,0 +1,161 @@
+/*     $NetBSD: pthread_sleep.c,v 1.1 2003/02/15 22:15:50 nathanw Exp $ */
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Nathan J. Williams.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <sys/cdefs.h>
+#include <sys/time.h>
+
+#include "pthread.h"
+#include "pthread_int.h"
+
+int    _sys_nanosleep(const struct timespec *, struct timespec *);
+
+extern int pthread__started;
+
+/*
+ * The point of this exercise is to avoid sleeping in the kernel for
+ * each and every thread that wants to sleep. A surprising number of
+ * applications create many threads that spend a lot of time sleeping.
+ *
+ * "Save a LWP, shoot a preppie."
+ */
+
+/* Queue of threads in nanosleep() */
+struct pthread_queue_t pthread__nanosleeping;
+static pthread_spin_t pt_nanosleep_lock;
+/*
+ * Nothing actually signals or waits on this lock, but the sleepobj
+ * needs to point to something.
+ */
+static pthread_cond_t pt_nanosleep_cond = PTHREAD_COND_INITIALIZER;
+
+static void pthread__nanosleep_callback(void *);
+
+
+int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+       int retval;
+       pthread_t self;
+       struct timespec sleeptime;
+       struct timeval now;
+       struct pt_alarm_t alarm;
+
+       if ((rqtp->tv_sec) < 0 ||
+           (rqtp->tv_nsec < 0) || (rqtp->tv_nsec > 1000000000L))
+               return EINVAL;
+
+       retval = 0;
+
+       self = pthread__self();
+
+       if (pthread__started == 0) {
+               pthread__testcancel(self);
+               retval = _sys_nanosleep(rqtp, rmtp);
+               pthread__testcancel(self);
+               return retval;
+       }
+
+       /*
+        * Figure out the absolute time to sleep until. If the thread
+        * got suspended before this then the sleep will be longer
+        * than intended, but the same thing could happen just before
+        * the thread called sleep too, so it's not our problem.
+        */
+       gettimeofday(&now, NULL);
+       TIMEVAL_TO_TIMESPEC(&now, &sleeptime);
+       timespecadd(&sleeptime, rqtp, &sleeptime);
+
+       pthread_spinlock(self, &pt_nanosleep_lock);
+       pthread_spinlock(self, &self->pt_statelock);
+       if (self->pt_cancel) {
+               pthread_spinunlock(self, &self->pt_statelock);
+               pthread_spinunlock(self, &pt_nanosleep_lock);
+               pthread_exit(PTHREAD_CANCELED);
+       }
+       pthread__alarm_add(self, &alarm, &sleeptime,
+           pthread__nanosleep_callback, self);
+           
+       self->pt_state = PT_STATE_BLOCKED_QUEUE;
+       self->pt_sleepobj = &pt_nanosleep_cond;
+       self->pt_sleepq = &pthread__nanosleeping;
+       self->pt_sleeplock = &pt_nanosleep_lock;
+       pthread_spinunlock(self, &self->pt_statelock);
+
+       PTQ_INSERT_TAIL(&pthread__nanosleeping, self, pt_sleep);
+       pthread__block(self, &pt_nanosleep_lock);
+       /* Spinlock is unlocked on return */
+       pthread__alarm_del(self, &alarm);
+
+       pthread__testcancel(self);
+
+       if (!pthread__alarm_fired(&alarm)) {
+               retval = -1;
+               errno = EINTR;
+               if (rmtp) {
+                       gettimeofday(&now, NULL);
+                       TIMEVAL_TO_TIMESPEC(&now, rmtp);
+                       timespecsub(&sleeptime, rmtp, rmtp);
+               }
+       }
+
+       return retval;
+}
+
+static void
+pthread__nanosleep_callback(void *arg)
+{
+       pthread_t self, thread;
+
+       thread = arg;
+       self = pthread__self();
+       /*
+        * Don't dequeue and schedule the thread if it's already been
+        * queued up by a signal or broadcast (but hasn't yet run as far
+        * as pthread__alarm_del(), or we wouldn't be here, and hence can't
+        * have become blocked on some *other* queue).
+        */
+       pthread_spinlock(self, &pt_nanosleep_lock);
+       if (thread->pt_state == PT_STATE_BLOCKED_QUEUE) {
+               PTQ_REMOVE(&pthread__nanosleeping, thread, pt_sleep);
+               pthread__sched(self, thread);
+       }
+       pthread_spinunlock(self, &pt_nanosleep_lock);
+}
+
+__strong_alias(_nanosleep, nanosleep)



Home | Main Index | Thread Index | Old Index